diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml index 9c96b2b40b2f15a3e834147dc7a64dcf30dcc9fd..d861d81c20844cfaa3a3492ae66deee17591eadd 100644 --- a/.idea/deploymentTargetDropDown.xml +++ b/.idea/deploymentTargetDropDown.xml @@ -5,6 +5,9 @@ <entry key="MainActivity"> <State /> </entry> + <entry key="SplashScreenActivity"> + <State /> + </entry> <entry key="app"> <State /> </entry> diff --git a/app/build.gradle.kts b/app/build.gradle.kts index c8ffaacfd02f4ff70792682940ab33dd713ef81c..e2f0395892c16b8bd15af1161fbbfbd73161a146 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -51,7 +51,9 @@ dependencies { implementation(libs.androidx.navigation.ui.ktx) implementation("com.squareup.retrofit2:retrofit:2.9.0") implementation("com.squareup.retrofit2:converter-gson:2.9.0") - implementation(libs.androidx.security.crypto) + implementation("androidx.security:security-crypto:1.0.0") + implementation("org.apache.poi:poi:5.2.4") + implementation("org.apache.poi:poi-ooxml:5.2.4") testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6b8ed3ddb2236f73b9c3b5c6a5b330363c34f30e..153034667596fe6cb8296d41ad3ee3209d057143 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,8 +1,22 @@ <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> + + <!-- Permissions --> <uses-permission android:name="android.permission.INTERNET" /> + <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> + <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" + tools:ignore="ProtectedPermissions" /> + + <queries> + <!-- Query GMail --> + <intent> + <action android:name="android.intent.action.SENDTO" /> + <data android:scheme="mailto" /> + </intent> + <!-- Add more queries for other email apps if needed --> + </queries> <application android:allowBackup="true" @@ -28,10 +42,34 @@ android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> - <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> + + <!-- Provider --> + <provider + android:name="androidx.core.content.FileProvider" + android:authorities="${applicationId}.provider" + android:exported="false" + android:grantUriPermissions="true"> + <meta-data + android:name="android.support.FILE_PROVIDER_PATHS" + android:resource="@xml/file_paths" /> + </provider> + <!-- Service --> + <service android:name="itb.bos.bondoman.services.JWTService" + android:exported="false" /> + + <!-- Broadcast Receiver --> + <receiver + android:name="itb.bos.bondoman.receivers.TokenExpiryBroadcastReceiver" + android:exported="false"> + <intent-filter> + <action android:name="itb.bos.bondoman.ACTION_TOKEN_EXPIRED" /> + </intent-filter> + </receiver> + + </application> </manifest> \ No newline at end of file diff --git a/app/src/main/java/itb/bos/bondoman/LogoutActivity.kt b/app/src/main/java/itb/bos/bondoman/LogoutActivity.kt index c3fc41ace1c662f21c43843bae112dda1a1145d6..208ef3189f1daba9ef483ba8a32b1507221f94e7 100644 --- a/app/src/main/java/itb/bos/bondoman/LogoutActivity.kt +++ b/app/src/main/java/itb/bos/bondoman/LogoutActivity.kt @@ -5,6 +5,7 @@ import android.os.Bundle import android.widget.Button import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.ViewModelProvider +import itb.bos.bondoman.helper.EmailHelper.Companion.sendTransactionsByEmail import itb.bos.bondoman.viewModel.AuthViewModel class LogoutActivity : AppCompatActivity() { @@ -22,5 +23,10 @@ class LogoutActivity : AppCompatActivity() { logoutButton.setOnClickListener { authViewModel.logout() } + + val sendEmailButton = findViewById<Button>(R.id.send_email_btn) + sendEmailButton.setOnClickListener { + sendTransactionsByEmail() + } } } diff --git a/app/src/main/java/itb/bos/bondoman/helper/EmailHelper.kt b/app/src/main/java/itb/bos/bondoman/helper/EmailHelper.kt new file mode 100644 index 0000000000000000000000000000000000000000..94b4ccae3a8c698a9950c2f6dece700fe621848b --- /dev/null +++ b/app/src/main/java/itb/bos/bondoman/helper/EmailHelper.kt @@ -0,0 +1,54 @@ +package itb.bos.bondoman.helper + +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.util.Log +import android.widget.Toast +import androidx.core.content.FileProvider +import itb.bos.bondoman.retrofit.data.Transaction +import java.io.File + +class EmailHelper { + + companion object { + fun sendTransactionsByEmail(context: Context, transactionList: List<Transaction>, fileFormat: String) { + // Log that the process has started + Log.d("EmailHelper", "Sending transactions by email started...") + + // Prepare the file path for the spreadsheet using SpreadsheetHelper + val filePath = SpreadsheetHelper.prepareSpreadsheetFile(context, transactionList, fileFormat) + + // Log the file path + Log.d("EmailHelper", "File path: $filePath") + + // Create intent to send email via GMail + val emailIntent = Intent(Intent.ACTION_SEND) + emailIntent.type = "message/rfc822" // MIME type for email + emailIntent.putExtra( + Intent.EXTRA_EMAIL, + arrayOf("arthur.vale4869@gmail.com") + ) // Set recipient email + emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Daftar Transaksi") // Set email subject + emailIntent.putExtra( + Intent.EXTRA_TEXT, + "Berikut adalah daftar transaksi terlampir." + ) // Set email text message + val fileUri = FileProvider.getUriForFile(context, "${context.packageName}.provider", File(filePath)) + emailIntent.putExtra(Intent.EXTRA_STREAM, fileUri) + + // Verify if there's any activity that can handle the intent + if (emailIntent.resolveActivity(context.packageManager) != null) { + context.startActivity(Intent.createChooser(emailIntent, "Send Email")) + // Log that the email has been sent + Log.d("EmailHelper", "Email sent successfully.") + } else { + // Handle case when there's no activity to handle the intent + Toast.makeText(context, "No email app found", Toast.LENGTH_SHORT).show() + // Log that no email app was found + Log.d("EmailHelper", "No email app found.") + } + } + } +} + diff --git a/app/src/main/java/itb/bos/bondoman/helper/NetworkHelper.kt b/app/src/main/java/itb/bos/bondoman/helper/NetworkHelper.kt new file mode 100644 index 0000000000000000000000000000000000000000..22d7acafab750e87397f67c6ac67e24c5770ae3e --- /dev/null +++ b/app/src/main/java/itb/bos/bondoman/helper/NetworkHelper.kt @@ -0,0 +1,45 @@ +package itb.bos.bondoman.helper + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.net.ConnectivityManager +import android.net.NetworkCapabilities +import android.os.Build +import android.widget.Toast + +interface NetworkStateListener { + fun onNetworkLost() +} + +class NetworkHelper(private val context: Context) { + + private var networkStateListener: NetworkStateListener? = null + + fun setNetworkStateListener(listener: NetworkStateListener) { + this.networkStateListener = listener + } + + fun isInternetAvailable(): Boolean { + var result = false + val connectivityManager = + context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager? + connectivityManager?.run { + connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork) + ?.run { + result = when { + hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true + hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true + else -> false + } + } + } + return result + } + + fun showNoInternetPopup() { + Toast.makeText(context, "No internet connection", Toast.LENGTH_SHORT).show() + } +} + + diff --git a/app/src/main/java/itb/bos/bondoman/helper/SpreadsheetHelper.kt b/app/src/main/java/itb/bos/bondoman/helper/SpreadsheetHelper.kt new file mode 100644 index 0000000000000000000000000000000000000000..40a8b182e1d4fb770fe208ea9084b76f73f78b1d --- /dev/null +++ b/app/src/main/java/itb/bos/bondoman/helper/SpreadsheetHelper.kt @@ -0,0 +1,52 @@ +package itb.bos.bondoman.helper + +import android.content.Context +import itb.bos.bondoman.retrofit.data.Transaction +import org.apache.poi.hssf.usermodel.HSSFWorkbook +import org.apache.poi.xssf.usermodel.XSSFWorkbook +import java.io.File +import java.io.FileOutputStream + +class SpreadsheetHelper { + + companion object { + // Dummy Transaction class for testing + fun prepareSpreadsheetFile(context: Context, transactionList: List<Transaction>, fileFormat: String): String { + // Create a new XSSFWorkbook or HSSFWorkbook based on the file format + val workbook = if (fileFormat == "xlsx") XSSFWorkbook() else HSSFWorkbook() + + // Create a new sheet + val sheet = workbook.createSheet("Transaction List") + + // Create a header row with all required columns + val headers = arrayOf("ID", "Name", "Amount", "Tanggal", "Kategori Transaksi", "Lokasi") + val headerRow = sheet.createRow(0) + for ((index, header) in headers.withIndex()) { + val cell = headerRow.createCell(index) + cell.setCellValue(header) + } + + // Populate data rows + for ((index, transaction) in transactionList.withIndex()) { + val row = sheet.createRow(index + 1) + row.createCell(0).setCellValue(transaction.id) + row.createCell(1).setCellValue(transaction.name) + row.createCell(2).setCellValue(transaction.amount) + // Set values for additional fields (Tanggal, Kategori Transaksi, Lokasi) + // Example: + row.createCell(3).setCellValue(transaction.date) + row.createCell(4).setCellValue(transaction.category) + row.createCell(5).setCellValue(transaction.location) + } + + // Write the workbook to a file + val fileName = "transaction_list.$fileFormat" + val file = File(context.filesDir, fileName) + FileOutputStream(file).use { + workbook.write(it) + } + + return file.absolutePath + } + } +} diff --git a/app/src/main/java/itb/bos/bondoman/receivers/NetworkChangeReceiver.kt b/app/src/main/java/itb/bos/bondoman/receivers/NetworkChangeReceiver.kt new file mode 100644 index 0000000000000000000000000000000000000000..0202d44a1df5bea207fae69278c6741ab0d84826 --- /dev/null +++ b/app/src/main/java/itb/bos/bondoman/receivers/NetworkChangeReceiver.kt @@ -0,0 +1,14 @@ +package itb.bos.bondoman.receivers + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import itb.bos.bondoman.helper.NetworkHelper + +class NetworkChangeReceiver(private val networkHelper: NetworkHelper) : BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + if (!networkHelper.isInternetAvailable()) { + networkHelper.showNoInternetPopup() + } + } +} diff --git a/app/src/main/java/itb/bos/bondoman/retrofit/data/TransactionData.kt b/app/src/main/java/itb/bos/bondoman/retrofit/data/TransactionData.kt new file mode 100644 index 0000000000000000000000000000000000000000..ac40e0b720b0c425621b18721f887f131acb4902 --- /dev/null +++ b/app/src/main/java/itb/bos/bondoman/retrofit/data/TransactionData.kt @@ -0,0 +1,13 @@ +package itb.bos.bondoman.retrofit.data + +import java.util.Date + +// Dummy Transaction +data class Transaction( + val id: String, + val name: String, + val amount: Double, + val date: Date, + val category: String, + val location: String +) \ No newline at end of file diff --git a/app/src/main/java/itb/bos/bondoman/services/JWTService.kt b/app/src/main/java/itb/bos/bondoman/services/JWTService.kt index e0fe824c630d2223b5d51c2b9af837621f0d4573..d70fb75923e95bd8944fadda9d32e7934a462528 100644 --- a/app/src/main/java/itb/bos/bondoman/services/JWTService.kt +++ b/app/src/main/java/itb/bos/bondoman/services/JWTService.kt @@ -17,7 +17,6 @@ class JWTService : Service() { private var isServiceRunning = false private lateinit var tokenHelper: TokenHelper - private val broadcastReceiver = TokenExpiryBroadcastReceiver() override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { if (!isServiceRunning) { diff --git a/app/src/main/res/layout/activity_logout.xml b/app/src/main/res/layout/activity_logout.xml index 27ba558e7487e650c3bdd3cd5b51953e845b5d86..e551c990b1bbb15081645f982a301a9740d23f4f 100644 --- a/app/src/main/res/layout/activity_logout.xml +++ b/app/src/main/res/layout/activity_logout.xml @@ -8,6 +8,16 @@ android:id="@+id/btn_logout" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="Logout" /> + android:text="Logout" + android:layout_alignParentTop="true" + android:layout_marginTop="16dp" /> -</RelativeLayout> \ No newline at end of file + <Button + android:id="@+id/send_email_btn" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Send Email" + android:layout_below="@id/btn_logout" + android:layout_marginTop="16dp" /> + +</RelativeLayout> diff --git a/app/src/main/res/xml/file_paths.xml b/app/src/main/res/xml/file_paths.xml new file mode 100644 index 0000000000000000000000000000000000000000..da0710177d1a8a1dcae250600df789286b32559c --- /dev/null +++ b/app/src/main/res/xml/file_paths.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<paths xmlns:android="http://schemas.android.com/apk/res/android"> + <files-path name="shared_files" path="." /> +</paths>