diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 2227d9b31ffb77ba7037604df029a436ae68e0fd..4efe4428e03b11a08b97f6e7e4cdb673a9813256 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -101,6 +101,9 @@ dependencies { api ("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3") api ("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3") + // POI: excel + implementation ("org.apache.poi:poi:5.0.0") + implementation ("org.apache.poi:poi-ooxml:5.2.3") //DataBinding kapt ("com.android.databinding:compiler:3.2.0-alpha10") diff --git a/app/src/main/java/com/example/nerbos/fragments/transaction/TransactionAdapter.kt b/app/src/main/java/com/example/nerbos/fragments/transaction/TransactionAdapter.kt index ae9cd893897417f02840a5358385352c0f221772..59629187d9c6e7c7d9348b03ba4d46e0b890c170 100644 --- a/app/src/main/java/com/example/nerbos/fragments/transaction/TransactionAdapter.kt +++ b/app/src/main/java/com/example/nerbos/fragments/transaction/TransactionAdapter.kt @@ -60,6 +60,10 @@ class TransactionAdapter() : RecyclerView.Adapter<TransactionAdapter.Transaction onLocationClick?.invoke(holder.location.text.toString()) } } + + fun getTransactionList() : List<Transaction>{ + return this.transactionList + } @SuppressLint("NotifyDataSetChanged") fun setData(transactions: List<Transaction>){ this.transactionList = transactions diff --git a/app/src/main/java/com/example/nerbos/fragments/transaction/TransactionFragment.kt b/app/src/main/java/com/example/nerbos/fragments/transaction/TransactionFragment.kt index 3a82a2c30bcd5f0fcc1dee02f6209844a1aca870..4fecdfe451ea52f823c5906d197fc59a9c1de253 100644 --- a/app/src/main/java/com/example/nerbos/fragments/transaction/TransactionFragment.kt +++ b/app/src/main/java/com/example/nerbos/fragments/transaction/TransactionFragment.kt @@ -1,20 +1,22 @@ package com.example.nerbos.fragments.transaction import android.Manifest -import android.app.AlertDialog import android.app.Dialog +import android.content.Context +import android.content.Context.STORAGE_SERVICE import android.content.Intent import android.content.pm.PackageManager -import android.location.Address import android.location.Geocoder import android.location.Location import android.os.Bundle +import android.os.Environment +import android.os.storage.StorageManager +import android.provider.SyncStateContract import android.text.TextUtils import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.view.Window import android.view.WindowManager import android.widget.Button import android.widget.EditText @@ -24,6 +26,8 @@ import android.widget.RadioGroup import android.widget.TextView import android.widget.Toast import androidx.core.app.ActivityCompat +import androidx.core.content.ContextCompat +import androidx.core.content.ContextCompat.getSystemService import androidx.fragment.app.Fragment import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProvider @@ -38,8 +42,21 @@ import com.example.nerbos.service.Authentication import com.example.nerbos.service.Utils import com.google.android.gms.location.FusedLocationProviderClient import com.google.android.gms.location.LocationServices -import com.google.android.gms.maps.CameraUpdateFactory -import com.google.android.gms.maps.model.LatLng +import org.apache.poi.hssf.usermodel.HSSFCell +import org.apache.poi.hssf.usermodel.HSSFRow +import org.apache.poi.hssf.usermodel.HSSFSheet +import org.apache.poi.hssf.usermodel.HSSFWorkbook +import org.apache.poi.ss.usermodel.Cell +import org.apache.poi.ss.usermodel.Row +import org.apache.poi.ss.usermodel.Sheet +import org.apache.poi.ss.usermodel.Workbook +import org.apache.poi.xssf.usermodel.XSSFSheet +import org.apache.poi.xssf.usermodel.XSSFWorkbook +import java.io.File +import java.io.FileNotFoundException +import java.io.FileOutputStream +import java.io.IOException +import java.io.OutputStream import java.util.Locale // TODO: Rename parameter arguments, choose names that match @@ -95,13 +112,105 @@ class TransactionFragment : Fragment() { transactionViewModel.readAllData!!.observe(viewLifecycleOwner, Observer { transactions -> transactionAdapter.setData(transactions) }) + // Add Transaction Button view.findViewById<ImageView>(R.id.addTransactionButton).setOnClickListener { showAddTransactionDialog() } + // Save Transaction + val xlsSave = view.findViewById<TextView>(R.id.xlsSave) + val xlsxSave = view.findViewById<TextView>(R.id.xlsxSave) + + view.findViewById<ImageView>(R.id.saveTransactionsButton).setOnClickListener{ + + if (xlsSave.visibility == View.VISIBLE){ + xlsSave.visibility = View.GONE + xlsxSave.visibility = View.GONE + } else if(xlsSave.visibility == View.GONE){ + xlsSave.visibility = View.VISIBLE + xlsxSave.visibility = View.VISIBLE + } + } + + xlsSave.setOnClickListener { + val workbook: Workbook = createExcelFile(transactionAdapter.getTransactionList(), "xls") + saveWorkBook(workbook, "xls") + xlsSave.visibility = View.GONE + xlsxSave.visibility = View.GONE + Toast.makeText(requireContext(), "Transaction Report.xls is downloaded", Toast.LENGTH_LONG).show() + } + + xlsxSave.setOnClickListener { + val workbook: Workbook = createExcelFile(transactionAdapter.getTransactionList(), "xlsx") + saveWorkBook(workbook, "xlsx") + xlsSave.visibility = View.GONE + xlsxSave.visibility = View.GONE + Toast.makeText(requireContext(), "Transaction Report.xlsx is downloaded", Toast.LENGTH_LONG).show() + } + return view } + private fun createExcelFile(transactions : List<Transaction>, extension: String) : Workbook{ + var workbook : Workbook + var sheet : Sheet + if (extension == "xls"){ + workbook = HSSFWorkbook() + sheet = workbook.createSheet("My Transactions") + } else { // "xlsx" + workbook = XSSFWorkbook() + sheet = workbook.createSheet("My Transactions") + } + + // Setup Header + val header : Row = sheet.createRow(0) + var cell : Cell = header.createCell(0) + cell.setCellValue("Date") + cell = header.createCell(1) + cell.setCellValue("Category") + cell = header.createCell(2) + cell.setCellValue("Nominal") + cell = header.createCell(3) + cell.setCellValue("Name") + cell = header.createCell(4) + cell.setCellValue("Location") + + // Fill the cell for transaction data + for (i in transactions.indices){ + val row : Row= sheet.createRow(i+1) + cell = row.createCell(0) + cell.setCellValue(transactions[i].date.toString()) + cell = row.createCell(1) + cell.setCellValue(transactions[i].category.toString()) + cell = row.createCell(2) + cell.setCellValue(transactions[i].nominal.toDouble()) + cell = row.createCell(3) + cell.setCellValue(transactions[i].name) + cell = row.createCell(4) + cell.setCellValue(transactions[i].location) + } + + return workbook + } + private fun saveWorkBook(workbook: Workbook, extension: String) { + val appDirectory = requireContext().filesDir + + val filepath:File = File(appDirectory , "Transaction Report.$extension") + + try{ + if(!filepath.exists()){ + filepath.createNewFile() + } + val fileOutputStream : FileOutputStream = FileOutputStream(filepath) + workbook.write(fileOutputStream) + fileOutputStream.flush() + fileOutputStream.close() + + }catch (e:Exception){ + e.printStackTrace() + } + } + private fun showLocationOnMap(location: String) { val mapIntent = Intent(requireActivity(), MapsActivity::class.java) mapIntent.putExtra("locationName", location) diff --git a/app/src/main/res/drawable/border_save_selection.xml b/app/src/main/res/drawable/border_save_selection.xml new file mode 100644 index 0000000000000000000000000000000000000000..8983d53e9a6d52fbc06654159d8ba3fb615ab910 --- /dev/null +++ b/app/src/main/res/drawable/border_save_selection.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item> + <shape android:shape="rectangle"> + <solid android:color="@color/base_bg" /> + </shape> + </item> + <item android:bottom="2dp"> + <shape android:shape="rectangle"> + <solid android:color="@color/white"/> + </shape> + </item> +</layer-list> diff --git a/app/src/main/res/drawable/button_save.png b/app/src/main/res/drawable/button_save.png new file mode 100644 index 0000000000000000000000000000000000000000..14956f537e47b091899be3f8065e3bd6994f2570 Binary files /dev/null and b/app/src/main/res/drawable/button_save.png differ diff --git a/app/src/main/res/drawable/button_send.png b/app/src/main/res/drawable/button_send.png new file mode 100644 index 0000000000000000000000000000000000000000..2a201a3dbd4d4953bb3cce8089a952608fa62835 Binary files /dev/null and b/app/src/main/res/drawable/button_send.png differ diff --git a/app/src/main/res/drawable/round_corner_save_selection.xml b/app/src/main/res/drawable/round_corner_save_selection.xml new file mode 100644 index 0000000000000000000000000000000000000000..8fc1858f38806ae67f85fb888c452f48786efc33 --- /dev/null +++ b/app/src/main/res/drawable/round_corner_save_selection.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <solid android:color="@color/white" /> + <corners android:bottomLeftRadius="10dp" android:bottomRightRadius="10dp" /> +</shape> \ 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 690063bd5c7b9d44d6d2de81aa99a259b4343789..97a7f7fb4d7c6ef4a46efdcb74294f48f99b7d3b 100644 --- a/app/src/main/res/layout/fragment_transaction.xml +++ b/app/src/main/res/layout/fragment_transaction.xml @@ -13,20 +13,40 @@ android:background="@color/base_bg" android:padding="20dp" > + <ImageView + android:id="@+id/saveTransactionsButton" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/button_save" + + android:layout_marginStart="10dp" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + android:contentDescription="@string/save_transactions_button" /> + + <ImageView + android:id="@+id/sendTransactionsButton" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/button_send" + android:layout_marginEnd="10dp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toTopOf="parent" + android:contentDescription="@string/send_transactions_button" /> <TextView android:id="@+id/myTransaction" android:layout_width="0sp" android:layout_height="wrap_content" - android:text="My Transaction" + android:text="@string/my_transaction" android:textColor="@color/white" android:textSize="20sp" android:textStyle="bold" android:layout_marginStart="10dp" - android:layout_marginTop="8dp" + android:layout_marginTop="40dp" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" + app:layout_constraintTop_toBottomOf="@+id/saveTransactionsButton" /> <ImageView @@ -34,12 +54,10 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/plus" - app:layout_constraintTop_toTopOf="parent" + android:layout_marginTop="30dp" + app:layout_constraintTop_toBottomOf="@id/sendTransactionsButton" app:layout_constraintEnd_toEndOf="parent" - > </ImageView> - - - + android:contentDescription="@string/add_transaction_button"/> <androidx.recyclerview.widget.RecyclerView android:layout_width="match_parent" @@ -49,5 +67,43 @@ app:layout_constraintTop_toBottomOf="@+id/myTransaction" /> + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="vertical" + android:layout_marginStart="28dp" + android:background="@drawable/round_corner_save_selection" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/saveTransactionsButton" > + + <TextView + android:id="@+id/xlsSave" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/xls" + android:background="@drawable/border_save_selection" + android:textSize="18sp" + android:textColor="@color/base_bg" + android:paddingTop="2dp" + android:paddingStart="30dp" + android:paddingBottom="4dp" + android:paddingEnd="30dp" + android:visibility="gone" + /> + + <TextView + android:id="@+id/xlsxSave" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="18sp" + android:textColor="@color/base_bg" + android:text="@string/xlsx" + android:paddingBottom="3dp" + android:paddingStart="26dp" + android:paddingEnd="30dp" + android:visibility="gone" + /> + </LinearLayout> + </androidx.constraintlayout.widget.ConstraintLayout> </FrameLayout> \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8238883239e177aab6c1d4abf47882760207137a..6508694d49a0ec60ef0ac02c5fd2ba041cf820ab 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -51,7 +51,14 @@ <string name="maps">Maps</string> <string name="network_sensing_string">No Internet Connection Please check your connection and try again.</string> <string name="close_button">Close Button</string> - + <string name="pie_chart">Pie Chart</string> + <string name="my_transaction">My Transaction</string> + <string name="add_transaction_button">Add Transaction Button</string> + <string name="send">Send</string> + <string name="save_transactions_button">Save Transactions Button</string> + <string name="send_transactions_button">Send Transactions Button</string> + <string name="xls">.xls</string> + <string name="xlsx">.xlsx</string> <string name="pie_chart_title">Income vs Outcome Chart</string> <string name="language_code">id</string> <string name="country_code">ID</string>