diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 5689a54d0c13bb4b709ec9d0bcbd942c38b3c734..37aa7deea566f4daaf225dd49ca7de61f0167b98 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -50,7 +50,9 @@ dependencies { implementation(libs.androidx.constraintlayout) implementation(libs.androidx.navigation.fragment.ktx) implementation(libs.androidx.navigation.ui.ktx) - testImplementation(libs.junit) + implementation(libs.poi) + implementation(libs.poi.ooxml) + testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) diff --git a/app/src/androidTest/java/com/example/bondoman/databases/TransactionDatabaseTest.kt b/app/src/androidTest/java/com/example/bondoman/databases/TransactionDatabaseTest.kt index 02d2fd454524b99e5df3670636ae1f6ff98b03d1..ef21ca67babcda9d65b7750eec59140a53783e22 100644 --- a/app/src/androidTest/java/com/example/bondoman/databases/TransactionDatabaseTest.kt +++ b/app/src/androidTest/java/com/example/bondoman/databases/TransactionDatabaseTest.kt @@ -51,7 +51,7 @@ class TransactionDatabaseTest { title = "Transaction 1", owner = user, category = TransactionCategory.EARNINGS, - amount = 100.0, + amount = 100L, ) val transaction2 = @@ -59,7 +59,7 @@ class TransactionDatabaseTest { title = "Transaction 2", owner = user, category = TransactionCategory.EARNINGS, - amount = 200.0, + amount = 200L, ) val transaction3 = @@ -67,7 +67,7 @@ class TransactionDatabaseTest { title = "Transaction 3", owner = user, category = TransactionCategory.EXPENSE, - amount = 100.0, + amount = 100L, ) repository.insert(transaction1, transaction2, transaction3) diff --git a/app/src/main/java/com/example/bondoman/data/repositories/UserRepository.kt b/app/src/main/java/com/example/bondoman/data/repositories/UserRepository.kt index 2c5283b39f5eddba072ac60846b0d815131b6ce7..fb787193e36e282569d09fab4ae7976c35668ce2 100644 --- a/app/src/main/java/com/example/bondoman/data/repositories/UserRepository.kt +++ b/app/src/main/java/com/example/bondoman/data/repositories/UserRepository.kt @@ -6,8 +6,11 @@ import com.example.bondoman.networks.responses.TokenResponse import com.example.bondoman.networks.services.UserService import retrofit2.Response -class UserRepository (private val service: UserService) { - suspend fun login(email: String, password: String): Response<LoginResponse> { +class UserRepository(private val service: UserService) { + suspend fun login( + email: String, + password: String, + ): Response<LoginResponse> { return service.login(LoginRequest(email, password)) } diff --git a/app/src/main/java/com/example/bondoman/data/utils/PreferencesManager.kt b/app/src/main/java/com/example/bondoman/data/utils/PreferencesManager.kt index 7df9205a5334716dd6505e01134a9f0d280d2290..30a505b50cff7e20b6c91cbfaf0c740c9d5d77fd 100644 --- a/app/src/main/java/com/example/bondoman/data/utils/PreferencesManager.kt +++ b/app/src/main/java/com/example/bondoman/data/utils/PreferencesManager.kt @@ -13,67 +13,95 @@ object PreferencesManager { } fun getEncryptedSharedPreferences(context: Context): SharedPreferences { - val masterKey = MasterKey.Builder(context) - .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) - .build() + val masterKey = + MasterKey.Builder(context) + .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) + .build() return EncryptedSharedPreferences.create( context, PREFS_NAME, masterKey, EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, - EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM + EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM, ) } - fun putString(context: Context, key: String, value: String, encrypted: Boolean = false) { - val editor = if (encrypted) { - getEncryptedSharedPreferences(context).edit() - } else { - getSharedPreferences(context).edit() - } + fun putString( + context: Context, + key: String, + value: String, + encrypted: Boolean = false, + ) { + val editor = + if (encrypted) { + getEncryptedSharedPreferences(context).edit() + } else { + getSharedPreferences(context).edit() + } editor.putString(key, value) editor.apply() } - fun getString(context: Context, key: String, encrypted: Boolean = false): String? { - val sharedPreferences = if (encrypted) { - getEncryptedSharedPreferences(context) - } else { - getSharedPreferences(context) - } + fun getString( + context: Context, + key: String, + encrypted: Boolean = false, + ): String? { + val sharedPreferences = + if (encrypted) { + getEncryptedSharedPreferences(context) + } else { + getSharedPreferences(context) + } return sharedPreferences.getString(key, null) } - fun putBoolean(context: Context, key: String, value: Boolean, encrypted: Boolean = false) { - val editor = if (encrypted) { - getEncryptedSharedPreferences(context).edit() - } else { - getSharedPreferences(context).edit() - } + fun putBoolean( + context: Context, + key: String, + value: Boolean, + encrypted: Boolean = false, + ) { + val editor = + if (encrypted) { + getEncryptedSharedPreferences(context).edit() + } else { + getSharedPreferences(context).edit() + } editor.putBoolean(key, value) editor.apply() } - fun getBoolean(context: Context, key: String, encrypted: Boolean = false): Boolean { - val sharedPreferences = if (encrypted) { - getEncryptedSharedPreferences(context) - } else { - getSharedPreferences(context) - } + fun getBoolean( + context: Context, + key: String, + encrypted: Boolean = false, + ): Boolean { + val sharedPreferences = + if (encrypted) { + getEncryptedSharedPreferences(context) + } else { + getSharedPreferences(context) + } return sharedPreferences.getBoolean(key, false) } - fun remove(context: Context, key: String, encrypted: Boolean = false) { - val editor = if (encrypted) { - getEncryptedSharedPreferences(context).edit() - } else { - getSharedPreferences(context).edit() - } + fun remove( + context: Context, + key: String, + encrypted: Boolean = false, + ) { + val editor = + if (encrypted) { + getEncryptedSharedPreferences(context).edit() + } else { + getSharedPreferences(context).edit() + } editor.remove(key) editor.apply() diff --git a/app/src/main/java/com/example/bondoman/data/viewmodels/login/LoginViewModel.kt b/app/src/main/java/com/example/bondoman/data/viewmodels/login/LoginViewModel.kt index e7b5618840222f27174e9ed3c3f6dfb94dd8b946..ae5cdbdcafd8a0b010c492fef8d627e9e76dc796 100644 --- a/app/src/main/java/com/example/bondoman/data/viewmodels/login/LoginViewModel.kt +++ b/app/src/main/java/com/example/bondoman/data/viewmodels/login/LoginViewModel.kt @@ -17,7 +17,10 @@ class LoginViewModel : ViewModel() { private val _tokenResponse = MutableLiveData<TokenResponse>() val tokenResponse = _tokenResponse - fun login(email: String, password: String) { + fun login( + email: String, + password: String, + ) { viewModelScope.launch { val repository = UserRepository(RetrofitClient.getInstance().create(UserService::class.java)) val loginResponse = repository.login(email, password) diff --git a/app/src/main/java/com/example/bondoman/data/viewmodels/settings/ExportTransactionResponseContainer.kt b/app/src/main/java/com/example/bondoman/data/viewmodels/settings/ExportTransactionResponseContainer.kt new file mode 100644 index 0000000000000000000000000000000000000000..076f025cff64cc7de61204631ab90b1e83592b5e --- /dev/null +++ b/app/src/main/java/com/example/bondoman/data/viewmodels/settings/ExportTransactionResponseContainer.kt @@ -0,0 +1,11 @@ +package com.example.bondoman.data.viewmodels.settings + +enum class ExportTransactionStatus { + SUCCESS, + FAILED, +} + +data class ExportTransactionResponseContainer( + val status: ExportTransactionStatus, + val message: String, +) diff --git a/app/src/main/java/com/example/bondoman/data/viewmodels/settings/SettingViewModel.kt b/app/src/main/java/com/example/bondoman/data/viewmodels/settings/SettingViewModel.kt index 742ee93118a4bad9a00581d143b34b7575af2b3f..eb8e9c9a2c9b222fe619832d7a7062631e090dfd 100644 --- a/app/src/main/java/com/example/bondoman/data/viewmodels/settings/SettingViewModel.kt +++ b/app/src/main/java/com/example/bondoman/data/viewmodels/settings/SettingViewModel.kt @@ -1,9 +1,129 @@ package com.example.bondoman.data.viewmodels.settings -import androidx.lifecycle.ViewModel +import android.app.Application +import android.content.ContentValues +import android.os.Environment +import android.provider.MediaStore +import android.util.Log +import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.viewModelScope +import com.example.bondoman.data.databases.TransactionDatabase +import com.example.bondoman.data.models.Transaction +import com.example.bondoman.data.repositories.TransactionRepository +import com.example.bondoman.data.repositories.UserRepository +import com.example.bondoman.networks.RetrofitClient +import com.example.bondoman.networks.services.UserService +import kotlinx.coroutines.launch +import org.apache.poi.ss.usermodel.Sheet +import org.apache.poi.ss.usermodel.Workbook +import org.apache.poi.xssf.usermodel.XSSFWorkbook +import java.text.SimpleDateFormat +import java.util.Date +import java.util.Locale + +class SettingViewModel(applicationContext: Application) : AndroidViewModel(applicationContext) { + private val _exportReportResponse = MutableLiveData<ExportTransactionResponseContainer>() + val exportReportResponse = _exportReportResponse -class SettingViewModel: ViewModel() { fun exportTransactionReport(bearerToken: String) { + viewModelScope.launch { + val userRepository = + UserRepository( + RetrofitClient.getInstanceWithAuth(bearerToken).create( + UserService::class.java, + ), + ) + + val response = userRepository.checkToken() + + if (!response.isSuccessful || response.body() == null) { + Log.d("SettingViewModel", "Response is failed") + _exportReportResponse.value = + ExportTransactionResponseContainer( + ExportTransactionStatus.FAILED, + response.errorBody()?.string() ?: "Unknown error", + ) + return@launch + } + + val transactionDB = TransactionDatabase.getInstance(getApplication()) + val transactionRepository = TransactionRepository(transactionDB.transactionDao()) + + val transactions = transactionRepository.getAll(response.body()!!.nim!!) + val workbook = transactionToExcel(transactions) + + try { + createExcel(workbook) + _exportReportResponse.value = + ExportTransactionResponseContainer( + ExportTransactionStatus.SUCCESS, + "Export Report Success", + ) + } catch (e: Exception) { + Log.e("SettingViewModel", e.message ?: "Unknown error") + _exportReportResponse.value = + ExportTransactionResponseContainer( + ExportTransactionStatus.FAILED, + e.message ?: "Unknown error", + ) + } + } + } + + private fun generateFileName(): String { + // Generate File Name based on current date and time + val sdf = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()) + return sdf.format(Date()) + } + + private fun createExcel(workbook: Workbook) { + // Save XLSX File to Downloads/Bondoman + val filename = generateFileName() + + val contentValues = + ContentValues().apply { + put(MediaStore.MediaColumns.DISPLAY_NAME, "$filename.xlsx") + put(MediaStore.MediaColumns.MIME_TYPE, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") + put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS + "/Bondoman") + } + + val uri = getApplication<Application>().contentResolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues) + val outputStream = getApplication<Application>().contentResolver.openOutputStream(uri!!) + workbook.write(outputStream) + outputStream?.close() + + workbook.close() + } + + private fun transactionToExcel(transactions: List<Transaction>): Workbook { + // Write transactions to XLSX File + val workbook = XSSFWorkbook() + val sheet: Sheet = workbook.createSheet("Transaction Report") + + createHeaderRow(sheet) + + transactions.forEachIndexed { index, transaction -> + val row = sheet.createRow(index + 1) + row.createCell(0).setCellValue(transaction.id.toDouble()) + row.createCell(1).setCellValue(transaction.title) + row.createCell(2).setCellValue(transaction.owner) + row.createCell(3).setCellValue(transaction.category.string) + row.createCell(4).setCellValue(transaction.amount.toDouble()) + row.createCell(5).setCellValue(transaction.date.toString()) + row.createCell(6).setCellValue(transaction.location) + } + + return workbook + } + + private fun createHeaderRow(sheet: Sheet) { + // Write Header Row + val headerRow = sheet.createRow(0) + val headerList = listOf("ID", "Title", "Owner", "Category", "Amount", "Date", "Location") + headerList.forEachIndexed { index, header -> + headerRow.createCell(index).setCellValue(header) + } } } diff --git a/app/src/main/java/com/example/bondoman/networks/RetrofitClient.kt b/app/src/main/java/com/example/bondoman/networks/RetrofitClient.kt index fd17a0c05fa348fb88f6f30d3d09fe02d643b374..1ab4be724c2987079ee5b9d365cb279a4b4d2791 100644 --- a/app/src/main/java/com/example/bondoman/networks/RetrofitClient.kt +++ b/app/src/main/java/com/example/bondoman/networks/RetrofitClient.kt @@ -10,19 +10,21 @@ import retrofit2.converter.moshi.MoshiConverterFactory object RetrofitClient { private const val BASE_URL = "https://pbd-backend-2024.vercel.app/" - private val moshi = Moshi.Builder() - .add(KotlinJsonAdapterFactory()) - .build() + private val moshi = + Moshi.Builder() + .add(KotlinJsonAdapterFactory()) + .build() private var instance: Retrofit? = null private var instanceWithAuth: Retrofit? = null fun getInstance(): Retrofit { if (instance == null) { - instance = Retrofit.Builder() - .baseUrl(BASE_URL) - .addConverterFactory(MoshiConverterFactory.create(moshi)) - .build() + instance = + Retrofit.Builder() + .baseUrl(BASE_URL) + .addConverterFactory(MoshiConverterFactory.create(moshi)) + .build() } return instance!! @@ -30,15 +32,17 @@ object RetrofitClient { fun getInstanceWithAuth(bearerToken: String): Retrofit { if (instanceWithAuth == null) { - val client = OkHttpClient.Builder() - .addInterceptor(AuthInterceptor(bearerToken)) - .build() - - instanceWithAuth = Retrofit.Builder() - .baseUrl(BASE_URL) - .addConverterFactory(MoshiConverterFactory.create(moshi)) - .client(client) - .build() + val client = + OkHttpClient.Builder() + .addInterceptor(AuthInterceptor(bearerToken)) + .build() + + instanceWithAuth = + Retrofit.Builder() + .baseUrl(BASE_URL) + .addConverterFactory(MoshiConverterFactory.create(moshi)) + .client(client) + .build() } return instanceWithAuth!! diff --git a/app/src/main/java/com/example/bondoman/networks/interceptors/AuthInterceptor.kt b/app/src/main/java/com/example/bondoman/networks/interceptors/AuthInterceptor.kt index c3d8dc12c094fb584b80d71485f3ee04b3dd21d9..0059c5c74de9ffd00ba6fcd365c4971de832b252 100644 --- a/app/src/main/java/com/example/bondoman/networks/interceptors/AuthInterceptor.kt +++ b/app/src/main/java/com/example/bondoman/networks/interceptors/AuthInterceptor.kt @@ -4,12 +4,12 @@ import okhttp3.Interceptor import okhttp3.Response class AuthInterceptor(private val bearerToken: String) : Interceptor { - override fun intercept(chain: Interceptor.Chain): Response { val request = chain.request() - val newRequest = request.newBuilder() - .addHeader("Authorization", "Bearer $bearerToken") - .build() + val newRequest = + request.newBuilder() + .addHeader("Authorization", "Bearer $bearerToken") + .build() return chain.proceed(newRequest) } diff --git a/app/src/main/java/com/example/bondoman/networks/requests/LoginRequest.kt b/app/src/main/java/com/example/bondoman/networks/requests/LoginRequest.kt index 67c6f6917c0f10662c3516a4307bd9914d7c1ae6..524f9eb7262a8d533a4e51b3d5497d73d5e5f770 100644 --- a/app/src/main/java/com/example/bondoman/networks/requests/LoginRequest.kt +++ b/app/src/main/java/com/example/bondoman/networks/requests/LoginRequest.kt @@ -4,10 +4,9 @@ import com.squareup.moshi.Json import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) -data class LoginRequest ( +data class LoginRequest( @Json(name = "email") var email: String? = null, - @Json(name = "password") var password: String? = null, ) diff --git a/app/src/main/java/com/example/bondoman/networks/responses/LoginResponse.kt b/app/src/main/java/com/example/bondoman/networks/responses/LoginResponse.kt index 80e739637bd66156d2fa19df30ac1bbd0529b2b0..5c22b9f864157b56da86eceab1390349a08c0b8b 100644 --- a/app/src/main/java/com/example/bondoman/networks/responses/LoginResponse.kt +++ b/app/src/main/java/com/example/bondoman/networks/responses/LoginResponse.kt @@ -5,6 +5,5 @@ import com.squareup.moshi.Json data class LoginResponse( @Json(name = "token") val token: String?, - val error: String?, ) diff --git a/app/src/main/java/com/example/bondoman/networks/responses/TokenResponse.kt b/app/src/main/java/com/example/bondoman/networks/responses/TokenResponse.kt index 09e84fe009aa2f46494c11acad7f3d29938adb85..1b0c07ecbf9df360efa7e25b688604a62a16751b 100644 --- a/app/src/main/java/com/example/bondoman/networks/responses/TokenResponse.kt +++ b/app/src/main/java/com/example/bondoman/networks/responses/TokenResponse.kt @@ -5,12 +5,9 @@ import com.squareup.moshi.Json data class TokenResponse( @Json(name = "nim") val nim: String?, - @Json(name = "iat") val iat: Int?, - @Json(name = "exp") val exp: Int?, - - val error: String? = null + val error: String? = null, ) diff --git a/app/src/main/java/com/example/bondoman/networks/services/UserService.kt b/app/src/main/java/com/example/bondoman/networks/services/UserService.kt index 1bea68903544d27fddb88454a67acbbd7ce8f4c6..184603967597439c4c664752b3fc03d87212d133 100644 --- a/app/src/main/java/com/example/bondoman/networks/services/UserService.kt +++ b/app/src/main/java/com/example/bondoman/networks/services/UserService.kt @@ -9,7 +9,9 @@ import retrofit2.http.POST interface UserService { @POST("/api/auth/login") - suspend fun login(@Body request: LoginRequest): Response<LoginResponse> + suspend fun login( + @Body request: LoginRequest, + ): Response<LoginResponse> @POST("/api/auth/token") suspend fun checkToken(): Response<TokenResponse> diff --git a/app/src/main/java/com/example/bondoman/views/activities/LoginActivity.kt b/app/src/main/java/com/example/bondoman/views/activities/LoginActivity.kt index 8acdbca3cc4f29efa90f5f0ce992e991d07d51dc..b81809ae67e6d7fc4dc407e92338e4019d272c7e 100644 --- a/app/src/main/java/com/example/bondoman/views/activities/LoginActivity.kt +++ b/app/src/main/java/com/example/bondoman/views/activities/LoginActivity.kt @@ -72,16 +72,17 @@ class LoginActivity : AppCompatActivity() { viewModel.login(email, password) - val observer = Observer<LoginResponse> { response -> - if (response.error != null) { - Toast.makeText(this, response.error, Toast.LENGTH_SHORT).show() - } else { - PreferencesManager.putString(this, "token", response.token ?: "", true) - val intent = Intent(this, MainActivity::class.java) - startActivity(intent) - finish() + val observer = + Observer<LoginResponse> { response -> + if (response.error != null) { + Toast.makeText(this, response.error, Toast.LENGTH_SHORT).show() + } else { + PreferencesManager.putString(this, "token", response.token ?: "", true) + val intent = Intent(this, MainActivity::class.java) + startActivity(intent) + finish() + } } - } viewModel.loginResponse.observe(this, observer) } @@ -95,23 +96,24 @@ class LoginActivity : AppCompatActivity() { viewModel.checkToken(token) - val observer = Observer<TokenResponse> { response -> - if (response.error != null) { - Log.e("LoginActivity", response.error) - return@Observer - } + val observer = + Observer<TokenResponse> { response -> + if (response.error != null) { + Log.e("LoginActivity", response.error) + return@Observer + } - val currentTime = System.currentTimeMillis() / 1000 - if (response.exp != null && response.exp < currentTime) { - Log.i("LoginActivity", "Token expired") - PreferencesManager.remove(this, "token", true) - return@Observer - } + val currentTime = System.currentTimeMillis() / 1000 + if (response.exp != null && response.exp < currentTime) { + Log.i("LoginActivity", "Token expired") + PreferencesManager.remove(this, "token", true) + return@Observer + } - val intent = Intent(this, MainActivity::class.java) - startActivity(intent) - finish() - } + val intent = Intent(this, MainActivity::class.java) + startActivity(intent) + finish() + } viewModel.tokenResponse.observe(this, observer) } diff --git a/app/src/main/java/com/example/bondoman/views/fragments/SettingsFragment.kt b/app/src/main/java/com/example/bondoman/views/fragments/SettingsFragment.kt index c753a209f81a3b7f56d5074d28a4bfb938d1fad0..b13dc87456f99452c5af5e0a0da47e42eec8fa7a 100644 --- a/app/src/main/java/com/example/bondoman/views/fragments/SettingsFragment.kt +++ b/app/src/main/java/com/example/bondoman/views/fragments/SettingsFragment.kt @@ -2,28 +2,23 @@ package com.example.bondoman.views.fragments import android.content.Intent 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.activity.viewModels import androidx.fragment.app.Fragment -import androidx.fragment.app.viewModels +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProvider import com.example.bondoman.R import com.example.bondoman.data.utils.PreferencesManager -import com.example.bondoman.data.viewmodels.login.LoginViewModel +import com.example.bondoman.data.viewmodels.settings.ExportTransactionResponseContainer +import com.example.bondoman.data.viewmodels.settings.ExportTransactionStatus import com.example.bondoman.data.viewmodels.settings.SettingViewModel import com.example.bondoman.views.activities.LoginActivity import com.example.bondoman.views.components.SettingButtonComponent -// TODO: Rename parameter arguments, choose names that match -// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER -private const val ARG_PARAM1 = "param1" -private const val ARG_PARAM2 = "param2" - class SettingsFragment : Fragment() { - private val settingViewModel: SettingViewModel by viewModels() + private lateinit var settingViewModel: SettingViewModel private lateinit var exportReportButton: SettingButtonComponent private lateinit var sendReportButton: SettingButtonComponent @@ -37,6 +32,7 @@ class SettingsFragment : Fragment() { ): View? { // Inflate the layout for this fragment val view = inflater.inflate(R.layout.fragment_settings, container, false) + settingViewModel = ViewModelProvider(this)[SettingViewModel::class.java] exportReportButton = view.findViewById(R.id.export_report_button) sendReportButton = view.findViewById(R.id.send_report_button) @@ -52,12 +48,24 @@ class SettingsFragment : Fragment() { } private fun onExportReportButtonClick() { - Toast.makeText(context, "Export Report", Toast.LENGTH_SHORT).show() - val token = PreferencesManager.getString(requireActivity(), "token", true) if (token != null) { settingViewModel.exportTransactionReport(token) + + val observer = + Observer<ExportTransactionResponseContainer> { + when (it.status) { + ExportTransactionStatus.SUCCESS -> { + Toast.makeText(context, "Export Report Success", Toast.LENGTH_SHORT).show() + } + ExportTransactionStatus.FAILED -> { + Toast.makeText(context, "Export Report Failed", Toast.LENGTH_SHORT).show() + } + } + } + + settingViewModel.exportReportResponse.observe(requireActivity(), observer) } } @@ -70,7 +78,7 @@ class SettingsFragment : Fragment() { } private fun onLogoutButtonClick() { - PreferencesManager.remove(requireActivity(),"token", true) + PreferencesManager.remove(requireActivity(), "token", true) val intent = Intent(requireActivity(), LoginActivity::class.java) startActivity(intent) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0575ba196d41bd55878dfca6ca8c64e5d4b3eab9..503587f539271e281005e3835ce3e2c24c404c9a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -17,6 +17,8 @@ mpChart = "v3.1.0" navigationFragmentKtx = "2.7.7" navigationUiKtx = "2.7.7" securityCrypto = "1.1.0-alpha06" +poi = "5.2.5" +poiOoxml = "5.2.5" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } @@ -45,6 +47,8 @@ mpchart = { module = "com.github.PhilJay:MPAndroidChart", version.ref = "mpChart androidx-navigation-fragment-ktx = { group = "androidx.navigation", name = "navigation-fragment-ktx", version.ref = "navigationFragmentKtx" } androidx-navigation-ui-ktx = { group = "androidx.navigation", name = "navigation-ui-ktx", version.ref = "navigationUiKtx" } retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" } +poi = { group = "org.apache.poi", name = "poi", version.ref = "poi" } +poi-ooxml = { group = "org.apache.poi", name = "poi-ooxml", version.ref = "poiOoxml" } [plugins] androidApplication = { id = "com.android.application", version.ref = "agp" }