diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml index e660996cbf03445ae8fb3a3acaa65ae3862be6d1..bea9a884573a8a489d0d04539efdfc9b1dd36aa8 100644 --- a/.idea/deploymentTargetDropDown.xml +++ b/.idea/deploymentTargetDropDown.xml @@ -20,18 +20,18 @@ </entry> <entry key="app"> <State> - <runningDeviceTargetSelectedWithDropDown> + <targetSelectedWithDropDown> <Target> - <type value="RUNNING_DEVICE_TARGET" /> + <type value="QUICK_BOOT_TARGET" /> <deviceKey> <Key> - <type value="SERIAL_NUMBER" /> - <value value="RR8N2068CCP" /> + <type value="VIRTUAL_DEVICE_PATH" /> + <value value="C:\Users\Muhamad\.android\avd\Resizable_API_33_1.avd" /> </Key> </deviceKey> </Target> - </runningDeviceTargetSelectedWithDropDown> - <timeTargetWasSelectedWithDropDown value="2024-03-12T08:14:37.565277300Z" /> + </targetSelectedWithDropDown> + <timeTargetWasSelectedWithDropDown value="2024-03-12T10:09:47.875397900Z" /> </State> </entry> </value> diff --git a/app/src/main/java/com/example/bondoman/ui/hub/HubActivity.kt b/app/src/main/java/com/example/bondoman/ui/hub/HubActivity.kt index ca22a2217b729828bb9cabbd08aa053ea9b6ca26..10ff1d7b50b85d3dd2415bae0b05286b23d40364 100644 --- a/app/src/main/java/com/example/bondoman/ui/hub/HubActivity.kt +++ b/app/src/main/java/com/example/bondoman/ui/hub/HubActivity.kt @@ -36,7 +36,6 @@ class HubActivity : AppCompatActivity() { // Initialize navbar and fragments val orientation = resources.configuration.orientation if(orientation == Configuration.ORIENTATION_LANDSCAPE){ - println("Window is landscape") landscape_binding = ActivityHubLandscapeBinding.inflate(layoutInflater) setContentView(landscape_binding.root) @@ -58,7 +57,6 @@ class HubActivity : AppCompatActivity() { navView.setupWithNavController(navController) } else{ - println("Window is portrait") portrait_binding = ActivityHubBinding.inflate(layoutInflater) setContentView(portrait_binding.root) diff --git a/app/src/main/java/com/example/bondoman/ui/hub/settings/SettingsFragment.kt b/app/src/main/java/com/example/bondoman/ui/hub/settings/SettingsFragment.kt index 860130cdd04421ea69d9192e58b8b4a25d22e2e5..b8d1a71ec5c7d94a46350d276e5f057c6d67e1f4 100644 --- a/app/src/main/java/com/example/bondoman/ui/hub/settings/SettingsFragment.kt +++ b/app/src/main/java/com/example/bondoman/ui/hub/settings/SettingsFragment.kt @@ -3,6 +3,7 @@ package com.example.bondoman.ui.hub.settings import android.Manifest import android.content.Intent import android.content.pm.PackageManager +import android.net.Uri import android.os.Bundle import android.os.Environment import android.view.LayoutInflater @@ -17,7 +18,6 @@ import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import com.example.bondoman.R -import com.example.bondoman.database.entity.TransactionEntity import com.example.bondoman.databinding.FragmentSettingsBinding import com.example.bondoman.ui.login.LoginActivity import com.example.bondoman.viewmodel.transaction.TransactionViewModel @@ -84,7 +84,14 @@ class SettingsFragment : Fragment() { headerCellStyle.setBorderRight(BorderStyle.THIN) // Initialize headers - val headers = arrayOf("No", "Title", "Category", "Amount", "Location", "Timestamp") + val headers = arrayOf( + getString(R.string.transaction_label_number), + getString(R.string.transaction_label_title), + getString(R.string.transaction_label_category), + getString(R.string.transaction_label_amount), + getString(R.string.transaction_label_location), + getString(R.string.transaction_label_timestamp) + ) val firstRow = workSheet.createRow(0) for ((index, header) in headers.withIndex()) { val cell = firstRow.createCell(index) @@ -136,7 +143,7 @@ class SettingsFragment : Fragment() { workbook.write(file.outputStream()) workbook.close() - Toast.makeText(requireContext(), "File saved at $path", Toast.LENGTH_SHORT).show() + Toast.makeText(requireContext(), getString(R.string.save_toast_success) + "$path", Toast.LENGTH_SHORT).show() // Open file immediately val intent = Intent(Intent.ACTION_VIEW) @@ -145,14 +152,114 @@ class SettingsFragment : Fragment() { startActivity(intent) } else{ - Toast.makeText(requireContext(), "Error: Data Unavailable", Toast.LENGTH_SHORT).show() + Toast.makeText(requireContext(), getString(R.string.settings_toast_uninitialized_viewmodel), Toast.LENGTH_SHORT).show() } } } - //TODO: Implement private fun sendTransaction(view: View){ - println("Transaction sent") + // Init with viewmodel + val transactionViewModel = ViewModelProvider(requireActivity()).get(TransactionViewModel::class.java) + transactionViewModel.list.observe(viewLifecycleOwner) { transactionList -> + if (transactionList != null){ + + // Initialize excel file + val workbook = XSSFWorkbook() + val workSheet = workbook.createSheet("Transactions") + val headerCellStyle = workbook.createCellStyle() + headerCellStyle.setFillForegroundColor(IndexedColors.LIGHT_GREEN.index) + headerCellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND) + headerCellStyle.setBorderTop(BorderStyle.THIN) + headerCellStyle.setBorderBottom(BorderStyle.THIN) + headerCellStyle.setBorderLeft(BorderStyle.THIN) + headerCellStyle.setBorderRight(BorderStyle.THIN) + + // Initialize headers + val headers = arrayOf( + getString(R.string.transaction_label_number), + getString(R.string.transaction_label_title), + getString(R.string.transaction_label_category), + getString(R.string.transaction_label_amount), + getString(R.string.transaction_label_location), + getString(R.string.transaction_label_timestamp) + ) + val firstRow = workSheet.createRow(0) + for ((index, header) in headers.withIndex()) { + val cell = firstRow.createCell(index) + cell.setCellValue(header) + cell.cellStyle = headerCellStyle + + workSheet.setColumnWidth(index, 6000) + } + workSheet.setColumnWidth(0, 2000) + + // Insert data + val cellStyle = headerCellStyle.copy() + cellStyle.setFillForegroundColor(IndexedColors.WHITE.index) + cellStyle.wrapText = true + + for ((index, transaction) in transactionList.withIndex()){ + val row = workSheet.createRow(1 + index) + + var cell = row.createCell(0) + cell.setCellValue((1 + index).toString()) + cell.cellStyle = cellStyle + + cell = row.createCell(1) + cell.setCellValue(transaction.title) + cell.cellStyle = cellStyle + + cell = row.createCell(2) + cell.setCellValue(transaction.category) + cell.cellStyle = cellStyle + + cell = row.createCell(3) + cell.setCellValue(transaction.amount.toDouble()) + cell.cellStyle = cellStyle + + cell = row.createCell(4) + cell.setCellValue(transaction.location) + cell.cellStyle = cellStyle + + cell = row.createCell(5) + cell.setCellValue(transaction.timestamp) + cell.cellStyle = cellStyle + } + + // Output file + val path = requireContext().cacheDir + val file = File( + path, + "BondomanTransaction" + SimpleDateFormat("yyyy_MM_dd_HH_mm_ss", Locale.getDefault()).format(Date()) + ".xlsx" + ) + workbook.write(file.outputStream()) + workbook.close() + + // Prep email + // TODO: set email recipient as the logged in account + val emailRecipient = arrayOf("13521095@std.stei.itb.ac.id") +// val emailIntent = Intent(Intent.ACTION_SENDTO, Uri.fromParts("mailto",emailRecipient, null)) + val emailIntent = Intent(Intent.ACTION_SEND) + emailIntent.type = "text/plain" + emailIntent.putExtra(Intent.EXTRA_EMAIL, emailRecipient) + emailIntent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.email_subject)) + emailIntent.putExtra(Intent.EXTRA_TEXT, getString(R.string.email_text) + SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(Date())) + emailIntent.putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(requireContext(), requireContext().packageName + ".provider", file)) + emailIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) + + // Send email + try { + startActivity(Intent.createChooser(emailIntent, "Send Email")) + Toast.makeText(requireContext(), getString(R.string.email_toast_success), Toast.LENGTH_SHORT).show() + } catch (e: Exception){ + println(e.message) + Toast.makeText(requireContext(), getString(R.string.email_toast_fail), Toast.LENGTH_SHORT).show() + } + } + else{ + Toast.makeText(requireContext(), getString(R.string.settings_toast_uninitialized_viewmodel), Toast.LENGTH_SHORT).show() + } + } } //TODO: Implement diff --git a/app/src/main/java/com/example/bondoman/ui/transaction/TransactionActivity.kt b/app/src/main/java/com/example/bondoman/ui/transaction/TransactionActivity.kt index 289747c42a05599857e4ed7ab743ba42370e270b..4b6cfe357f4868c21da5bf842f6b56d98671d7e3 100644 --- a/app/src/main/java/com/example/bondoman/ui/transaction/TransactionActivity.kt +++ b/app/src/main/java/com/example/bondoman/ui/transaction/TransactionActivity.kt @@ -57,10 +57,10 @@ class TransactionActivity : AppCompatActivity() { val amount = binding.amountInput.text.toString() if (title.isEmpty()){ - Toast.makeText(this, "Please enter a title", Toast.LENGTH_SHORT).show() + Toast.makeText(this, getString(R.string.transaction_add_toast_error_title), Toast.LENGTH_SHORT).show() } else if (amount.isEmpty()){ - Toast.makeText(this, "Please enter an amount", Toast.LENGTH_SHORT).show() + Toast.makeText(this, getString(R.string.transaction_add_toast_error_amount), Toast.LENGTH_SHORT).show() } else{ transactionViewModel.insert( @@ -74,7 +74,7 @@ class TransactionActivity : AppCompatActivity() { timestamp = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(Date()) ) ) - Toast.makeText(this, "Transaction saved successfully", Toast.LENGTH_SHORT).show() + Toast.makeText(this, getString(R.string.transaction_add_toast_success), Toast.LENGTH_SHORT).show() // TODO: Delete, this is for testing purposes // transactionViewModel.deleteAll() onBackPressed() diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d0dcc486c44283c089540290d5beb522e7da6941..cfe0d3882913d8cab94e2e361cfb08ffa1f5d063 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -10,19 +10,34 @@ <string name="login_label_password">Password</string> <string name="login_label_enter">Login</string> + <string name="transaction_label_number">No</string> <string name="transaction_label_title">Title</string> <string name="transaction_label_amount">Amount</string> <string name="transaction_label_category">Category</string> <string name="transaction_label_location">Location</string> + <string name="transaction_label_timestamp">Timestamp</string> <string name="transaction_label_submit">Submit</string> <string name="transaction_category_income">Income</string> <string name="transaction_category_expenses">Expenses</string> + <string name="transaction_add_toast_error_title">Please enter a title</string> + <string name="transaction_add_toast_error_amount">Please enter an amount</string> + <string name="transaction_add_toast_success">Transaction saved successfully</string> + <string name="settings_save_transaction">Save transaction list</string> <string name="settings_send_transaction">Send transaction list</string> <string name="settings_logout">Log out</string> + <string name="email_subject">Bondoman: Transaction Data</string> + <string name="email_text">Attached are transaction + data from Bondoman, data is recorded at </string> + <string name="email_toast_success">Sending file...</string> + <string name="email_toast_fail">Failed to send file</string> + + <string name="save_toast_success">File saved at </string> + <string name="settings_toast_uninitialized_viewmodel">Error: Data Unavailable</string> + <string-array name="category_choices"> <item>Income</item> <item>Expenses</item> diff --git a/app/src/main/res/xml/provider_paths.xml b/app/src/main/res/xml/provider_paths.xml index 4495c28c86d1340dba06826bf7a03519fe25aa88..4e0091cf0a8b1fe2986d4a692cffa2690d3f8ae7 100644 --- a/app/src/main/res/xml/provider_paths.xml +++ b/app/src/main/res/xml/provider_paths.xml @@ -1,4 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> <paths> <external-path name="external_files" path="."/> + <cache-path name="cache" path="." /> </paths> \ No newline at end of file