diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 82eb6647a6a2659f89516714c79f5722838a46b3..2f28c6f3de5bd9004c530e4214bc9e7e4d6c05e0 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -91,6 +91,8 @@ dependencies { api("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutine") api("org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutine") + implementation("com.github.PhilJay:MPAndroidChart:v3.1.0") + // UI implementation("androidx.constraintlayout:constraintlayout:$rootProject.constraintLayoutVersion") implementation("com.google.android.material:material:$rootProject.materialVersion") @@ -114,8 +116,8 @@ dependencies { testImplementation("org.mockito:mockito-core:3.12.4") // Location - implementation("com.google.android.gms:play-services-location:18.0.0") - + implementation("com.google.android.gms:play-services-location:21.2.0") + implementation("com.google.android.gms:play-services-maps:18.2.0") //okHttp diff --git a/app/src/androidTest/java/com/example/pbd_jwr/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/example/pbd_jwr/ExampleInstrumentedTest.kt index e547afbdffe2c18d21fe8ab00c693c4701e07183..b33e06fe921e568be4e504bdd3814ecc7c596f11 100644 --- a/app/src/androidTest/java/com/example/pbd_jwr/ExampleInstrumentedTest.kt +++ b/app/src/androidTest/java/com/example/pbd_jwr/ExampleInstrumentedTest.kt @@ -26,9 +26,7 @@ package com.example.pbd_jwr import androidx.room.Room import androidx.test.platform.app.InstrumentationRegistry import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.example.pbd_jwr.data.dao.UserDao import com.example.pbd_jwr.data.database.AppDatabase -import com.example.pbd_jwr.data.entity.User import kotlinx.coroutines.runBlocking import org.junit.After import org.junit.Before diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0f9839a49d2343fbe5b7e42d569895b3b08055a1..2563d894d8155def992d4597a7e543de86a5e9b8 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -37,6 +37,19 @@ <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> + + <meta-data + android:name="com.google.android.geo.API_KEY" + android:value="AIzaSyCY4EHrVn_0agFwVs8q2F5wyx55pt-eJF4" /> + + <receiver + android:name=".TransactionAddFragment" + android:enabled="true" + android:exported="true"> + <intent-filter> + <action android:name="com.example.pbd_jwr.RANDOMIZE_TRANSACTION" /> + </intent-filter> + </receiver> <activity android:name=".MainActivity" android:exported="true" diff --git a/app/src/main/java/com/example/pbd_jwr/MainActivity.kt b/app/src/main/java/com/example/pbd_jwr/MainActivity.kt index a1fe06724a23b6bbd0b61a1aca05b97ccdd42294..d6f63f836bca279b93e90bfb9404a03bf4bd1c57 100644 --- a/app/src/main/java/com/example/pbd_jwr/MainActivity.kt +++ b/app/src/main/java/com/example/pbd_jwr/MainActivity.kt @@ -23,6 +23,7 @@ import androidx.navigation.ui.setupActionBarWithNavController import androidx.navigation.ui.setupWithNavController import com.example.pbd_jwr.backgroundService.JWTValidationService import com.example.pbd_jwr.data.entity.Transaction +import com.example.pbd_jwr.data.model.Category import com.example.pbd_jwr.databinding.ActivityMainBinding import com.example.pbd_jwr.encryptedSharedPref.EncryptedSharedPref import com.example.pbd_jwr.network.NetworkCallbackImplementation @@ -192,6 +193,10 @@ class MainActivity : AppCompatActivity() { private val startScanActivityForResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> if (result.resultCode == Activity.RESULT_OK) { + + sharedPreferences = EncryptedSharedPref.create(applicationContext, "login") + val currentUserEmail = sharedPreferences.getString("email", "") ?: "" + val data = result.data val transactionDummyData = data?.getStringExtra("transactionDummyData") @@ -203,7 +208,7 @@ class MainActivity : AppCompatActivity() { for (i in 0 until itemsArray.length()) { val itemObject = itemsArray.getJSONObject(i) val name = itemObject.getString("name") - val category = "expense" + val category = Category.EXPENSE val price = itemObject.getDouble("price") val qty = itemObject.getInt("qty") val amount = (qty * price * 1000).roundToInt() / 1000.0 @@ -212,7 +217,7 @@ class MainActivity : AppCompatActivity() { val location = "Latitude: $latitude, Longitude: $longitude" val date = Date().time - mTransactionViewModel.addTransaction(Transaction(userId = 1, title = name, category = category, amount = amount, location = location, date = date)) + mTransactionViewModel.addTransaction(Transaction(email = currentUserEmail, title = name, category = category, amount = amount, latitude = latitude, longitude = longitude, date = date)) } diff --git a/app/src/main/java/com/example/pbd_jwr/converters/CategoryConverter.kt b/app/src/main/java/com/example/pbd_jwr/converters/CategoryConverter.kt new file mode 100644 index 0000000000000000000000000000000000000000..93ad6cf0f9e51feb82b799b98e0bc66a7fb8dd25 --- /dev/null +++ b/app/src/main/java/com/example/pbd_jwr/converters/CategoryConverter.kt @@ -0,0 +1,20 @@ +package com.example.pbd_jwr.converters + +import androidx.room.TypeConverter +import com.example.pbd_jwr.data.model.Category + +class CategoryConverter { + @TypeConverter + fun fromString(value: String): Category { + return when (value) { + "INCOME" -> Category.INCOME + "EXPENSE" -> Category.EXPENSE + else -> throw IllegalArgumentException("Unknown category: $value") + } + } + + @TypeConverter + fun toString(category: Category): String { + return category.name + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/pbd_jwr/data/dao/TransactionDao.kt b/app/src/main/java/com/example/pbd_jwr/data/dao/TransactionDao.kt index 977a58f9b0c74cb115e550698ac1e4984429a8af..77763290abe2b602d54314d8b6ac8fd0322414ad 100644 --- a/app/src/main/java/com/example/pbd_jwr/data/dao/TransactionDao.kt +++ b/app/src/main/java/com/example/pbd_jwr/data/dao/TransactionDao.kt @@ -8,12 +8,16 @@ import androidx.room.OnConflictStrategy import androidx.room.Query import androidx.room.Update import com.example.pbd_jwr.data.entity.Transaction +import java.util.Locale.Category @Dao interface TransactionDao { @Query("SELECT * FROM `transaction`") fun getAllTransactions(): LiveData<List<Transaction>> + @Query("SELECT * FROM `transaction` WHERE email = :email") + fun getTransactionsByEmail(email: String): LiveData<List<Transaction>> + @Insert(onConflict = OnConflictStrategy.ABORT) suspend fun addTransaction(transaction: Transaction) diff --git a/app/src/main/java/com/example/pbd_jwr/data/dao/UserDao.kt b/app/src/main/java/com/example/pbd_jwr/data/dao/UserDao.kt deleted file mode 100644 index 1efeb6d98df83eac7ed21d956b47a3f4e48e7d5d..0000000000000000000000000000000000000000 --- a/app/src/main/java/com/example/pbd_jwr/data/dao/UserDao.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.example.pbd_jwr.data.dao - -import androidx.lifecycle.LiveData -import androidx.room.Dao -import androidx.room.Insert -import androidx.room.OnConflictStrategy -import androidx.room.Query -import com.example.pbd_jwr.data.entity.User - -@Dao -interface UserDao { - @Query("SELECT * FROM user") - fun getAllUsers(): LiveData<List<User>> - - @Insert(onConflict = OnConflictStrategy.ABORT) - suspend fun createUser(user: User) -} \ No newline at end of file diff --git a/app/src/main/java/com/example/pbd_jwr/data/database/AppDatabase.kt b/app/src/main/java/com/example/pbd_jwr/data/database/AppDatabase.kt index 35cda16e708444f7737a9dfdc36f03ebbdc27e96..f6bdc6cca26cf8e7a3e680d30862a781bd32005f 100644 --- a/app/src/main/java/com/example/pbd_jwr/data/database/AppDatabase.kt +++ b/app/src/main/java/com/example/pbd_jwr/data/database/AppDatabase.kt @@ -4,18 +4,19 @@ import android.content.Context import androidx.room.Database import androidx.room.Room import androidx.room.RoomDatabase +import androidx.room.TypeConverters import androidx.sqlite.db.SupportSQLiteDatabase +import com.example.pbd_jwr.converters.CategoryConverter import com.example.pbd_jwr.data.dao.TransactionDao -import com.example.pbd_jwr.data.dao.UserDao import com.example.pbd_jwr.data.entity.Transaction -import com.example.pbd_jwr.data.entity.User +import com.example.pbd_jwr.data.model.Category import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -@Database(entities = [User::class, Transaction::class], version = 1) +@Database(entities = [Transaction::class], version = 3) +@TypeConverters(CategoryConverter::class) abstract class AppDatabase : RoomDatabase() { - abstract fun userDao(): UserDao abstract fun transactionDao(): TransactionDao companion object { @@ -34,6 +35,7 @@ abstract class AppDatabase : RoomDatabase() { "app_database" ) .addCallback(DatabaseCallback(context)) + .fallbackToDestructiveMigration() .build() INSTANCE = instance return instance @@ -46,67 +48,68 @@ abstract class AppDatabase : RoomDatabase() { super.onCreate(db) INSTANCE?.let { database -> CoroutineScope(Dispatchers.IO).launch { - populateDatabase(database.userDao(), database.transactionDao()) + populateDatabase(database.transactionDao()) } } } - private suspend fun populateDatabase(userDao: UserDao, transactionDao: TransactionDao) { - // Seed users - val user1 = User(fullName = "John Doe", email = "john@example.com") - val user2 = User(fullName = "Jane Doe", email = "jane@example.com") - userDao.createUser(user1) - userDao.createUser(user2) - + private suspend fun populateDatabase(transactionDao: TransactionDao) { // Seed transactions val transaction1 = Transaction( - userId = user1.id, + email = "13521103@std.stei.itb.ac.id", title = "Transaction 1", - category = "Category 1", + category = Category.INCOME, amount = 100.0, - location = "Location 1", + latitude = -6.2088, + longitude = 106.8456, date = System.currentTimeMillis() ) val transaction2 = Transaction( - userId = user2.id, + email = "13521103@std.stei.itb.ac.id", title = "Transaction 2", - category = "Category 2", + category = Category.EXPENSE, amount = 200.0, - location = "Location 2", + latitude = -6.2188, + longitude = 106.8399, date = System.currentTimeMillis() ) val transaction3 = Transaction( - userId = user2.id, - title = "Transaction 3", - category = "Category 3", - amount = 300.0, - location = "Location 3", - date = System.currentTimeMillis() + email = "13521103@std.stei.itb.ac.id", + title = "Transaction 3", + category = Category.INCOME, + amount = 300.0, + latitude = -6.2024, + longitude = 106.8247, + date = System.currentTimeMillis() ) val transaction4 = Transaction( - userId = user2.id, - title = "Transaction 4", - category = "Category 4", - amount = 400.0, - location = "Location 4", - date = System.currentTimeMillis() + email = "13521103@std.stei.itb.ac.id", + title = "Transaction 4", + category = Category.EXPENSE, + amount = 400.0, + latitude = -6.2426, + longitude = 106.8000, + date = System.currentTimeMillis() ) val transaction5 = Transaction( - userId = user1.id, - title = "Transaction 5", - category = "Category 5", - amount = 500.0, - location = "Location 5", - date = System.currentTimeMillis() + email = "13521103@std.stei.itb.ac.id", + title = "Transaction 5", + category = Category.EXPENSE, + amount = 500.0, + latitude = -6.2787, + longitude = 106.8467, + date = System.currentTimeMillis() ) val transaction6 = Transaction( - userId = user1.id, - title = "Transaction 6", - category = "Category 6", - amount = 600.0, - location = "Location 6", - date = System.currentTimeMillis() + email = "13521103@std.stei.itb.ac.id", + title = "Transaction 6", + category = Category.INCOME, + amount = 600.0, + latitude = -6.2475, + longitude = 107.1485, + date = System.currentTimeMillis() ) + transactionDao.addTransaction(transaction1) transactionDao.addTransaction(transaction2) transactionDao.addTransaction(transaction3) diff --git a/app/src/main/java/com/example/pbd_jwr/data/entity/Transaction.kt b/app/src/main/java/com/example/pbd_jwr/data/entity/Transaction.kt index 0e68ab499f680c3fe2e0f087c132dc0bad36e866..415ef33c9ca097905106a38b6d0a5868bc25f882 100644 --- a/app/src/main/java/com/example/pbd_jwr/data/entity/Transaction.kt +++ b/app/src/main/java/com/example/pbd_jwr/data/entity/Transaction.kt @@ -4,16 +4,20 @@ import android.os.Parcelable import kotlinx.parcelize.Parcelize import androidx.room.Entity import androidx.room.PrimaryKey +import androidx.room.TypeConverters +import com.example.pbd_jwr.converters.CategoryConverter +import com.example.pbd_jwr.data.model.Category @Parcelize @Entity(tableName = "transaction") data class Transaction( @PrimaryKey(autoGenerate = true) val id: Long = 0, - val userId: Long, + val email: String, val title: String, - val category: String, + @TypeConverters(CategoryConverter::class) + val category: Category, val amount: Double, - val location: String, + val latitude: Double, + val longitude: Double, val date: Long -): Parcelable - +): Parcelable \ No newline at end of file diff --git a/app/src/main/java/com/example/pbd_jwr/data/entity/User.kt b/app/src/main/java/com/example/pbd_jwr/data/entity/User.kt deleted file mode 100644 index e86d15be859819a6b3a39eb0cb1a5cdf5bae4b6e..0000000000000000000000000000000000000000 --- a/app/src/main/java/com/example/pbd_jwr/data/entity/User.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.example.pbd_jwr.data.entity - -import androidx.room.Entity -import androidx.room.PrimaryKey - -@Entity(tableName = "user") -data class User( - @PrimaryKey(autoGenerate = true) - val id: Long = 0, - val fullName: String, - val email: String, -) \ No newline at end of file diff --git a/app/src/main/java/com/example/pbd_jwr/data/model/CategoryModel.kt b/app/src/main/java/com/example/pbd_jwr/data/model/CategoryModel.kt new file mode 100644 index 0000000000000000000000000000000000000000..056b9fe5416520eef685935a27c2186d706cbcdc --- /dev/null +++ b/app/src/main/java/com/example/pbd_jwr/data/model/CategoryModel.kt @@ -0,0 +1,6 @@ +package com.example.pbd_jwr.data.model + +enum class Category { + INCOME, + EXPENSE +} \ No newline at end of file diff --git a/app/src/main/java/com/example/pbd_jwr/data/repository/TransactionRepository.kt b/app/src/main/java/com/example/pbd_jwr/data/repository/TransactionRepository.kt index 8ea9c9020457758397a04f8c8c93d1ff75e7be98..325fbbabdd9bd1b0714b6acb799671dc0ff4ba79 100644 --- a/app/src/main/java/com/example/pbd_jwr/data/repository/TransactionRepository.kt +++ b/app/src/main/java/com/example/pbd_jwr/data/repository/TransactionRepository.kt @@ -3,12 +3,17 @@ package com.example.pbd_jwr.data.repository import androidx.lifecycle.LiveData import com.example.pbd_jwr.data.dao.TransactionDao import com.example.pbd_jwr.data.entity.Transaction +import java.util.Locale.Category class TransactionRepository(private val transactionDao: TransactionDao) { fun getAllTransactions(): LiveData<List<Transaction>> { return transactionDao.getAllTransactions() } + fun getTransactionsByEmail(email: String): LiveData<List<Transaction>> { + return transactionDao.getTransactionsByEmail(email) + } + suspend fun addTransaction(transaction: Transaction) { transactionDao.addTransaction(transaction) } diff --git a/app/src/main/java/com/example/pbd_jwr/data/repository/UserRepository.kt b/app/src/main/java/com/example/pbd_jwr/data/repository/UserRepository.kt deleted file mode 100644 index 35b47c2a4f5ac4147e0269796126748ed38c4b9b..0000000000000000000000000000000000000000 --- a/app/src/main/java/com/example/pbd_jwr/data/repository/UserRepository.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.example.pbd_jwr.data.repository - -import androidx.lifecycle.LiveData -import com.example.pbd_jwr.data.dao.UserDao -import com.example.pbd_jwr.data.entity.User - -class UserRepository(private val userDao: UserDao) { - - fun getAllUsers(): LiveData<List<User>> { - return userDao.getAllUsers() - } - - suspend fun createUser(user: User) { - userDao.createUser(user) - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/example/pbd_jwr/ui/dashboard/DashboardFragment.kt b/app/src/main/java/com/example/pbd_jwr/ui/dashboard/DashboardFragment.kt index e518c7a8642989047e94238f9b9a7e97a54e73cc..12da78b569d6314edb9d3d833b15c367ac2014cc 100644 --- a/app/src/main/java/com/example/pbd_jwr/ui/dashboard/DashboardFragment.kt +++ b/app/src/main/java/com/example/pbd_jwr/ui/dashboard/DashboardFragment.kt @@ -54,8 +54,12 @@ class DashboardFragment : Fragment() { val entries = ArrayList<PieEntry>() for ((category, total) in totalPerCategory) { - entries.add(PieEntry(total.toFloat(), - category.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.ROOT) else it.toString() })) + entries.add( + PieEntry( + total.toFloat(), + category.name.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.ROOT) else it.toString() } + ) + ) } val dataSet = PieDataSet(entries, "Categories") diff --git a/app/src/main/java/com/example/pbd_jwr/ui/map/MapFragment.kt b/app/src/main/java/com/example/pbd_jwr/ui/map/MapFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..c44e5af496265760cb696ec1b49a555ae3f930d6 --- /dev/null +++ b/app/src/main/java/com/example/pbd_jwr/ui/map/MapFragment.kt @@ -0,0 +1,50 @@ +//package com.example.pbd_jwr.ui.map +// +//import android.os.Bundle +//import android.view.LayoutInflater +//import android.view.View +//import android.view.ViewGroup +//import androidx.fragment.app.Fragment +//import com.example.pbd_jwr.databinding.FragmentMapsBinding +//import com.google.android.gms.maps.CameraUpdateFactory +//import com.google.android.gms.maps.GoogleMap +//import com.google.android.gms.maps.OnMapReadyCallback +//import com.google.android.gms.maps.SupportMapFragment +//import com.google.android.gms.maps.model.LatLng +//import com.google.android.gms.maps.model.MarkerOptions +// +//class MapsFragment : Fragment(), OnMapReadyCallback { +// +// private lateinit var mMap: GoogleMap +// +// private var _binding: FragmentMapsBinding? = null +// private val binding get() = _binding!! +// +// override fun onCreateView( +// inflater: LayoutInflater, +// container: ViewGroup?, +// savedInstanceState: Bundle? +// ): View? { +// _binding = FragmentMapsBinding.inflate(inflater, container, false) +// val root: View = binding.root +// +// val mapFragment = childFragmentManager.findFragmentById(R.id.map_container) as SupportMapFragment +// mapFragment.getMapAsync(this) +// +// return root +// } +// +// override fun onDestroyView() { +// super.onDestroyView() +// _binding = null +// } +// +// override fun onMapReady(googleMap: GoogleMap) { +// mMap = googleMap +// +// // Add a marker in a default location and move the camera +// val defaultLocation = LatLng(-34.0, 151.0) +// mMap.addMarker(MarkerOptions().position(defaultLocation).title("Marker in Default Location")) +// mMap.moveCamera(CameraUpdateFactory.newLatLng(defaultLocation)) +// } +//} diff --git a/app/src/main/java/com/example/pbd_jwr/ui/settings/SettingsFragment.kt b/app/src/main/java/com/example/pbd_jwr/ui/settings/SettingsFragment.kt index ba30aa388a0e694192026318ea431e550d5e4db0..8904abe133f1d1de17dc762d133eb79cb1e20169 100644 --- a/app/src/main/java/com/example/pbd_jwr/ui/settings/SettingsFragment.kt +++ b/app/src/main/java/com/example/pbd_jwr/ui/settings/SettingsFragment.kt @@ -3,6 +3,7 @@ package com.example.pbd_jwr.ui.settings import android.content.ContentValues import android.content.Context import android.content.Intent +import androidx.localbroadcastmanager.content.LocalBroadcastManager import android.content.SharedPreferences import android.net.Uri import android.os.Bundle @@ -50,6 +51,14 @@ class SettingsFragment : Fragment() { saveTransactionsToExcel() } + val randomizeButton = binding.randomTransactionBtn + randomizeButton.setOnClickListener { + val intent = Intent() + intent.setAction("com.example.pbd_jwr.RANDOMIZE_TRANSACTION") + + LocalBroadcastManager.getInstance(requireContext()).sendBroadcast(intent) + } + binding.twibbonButton.setOnClickListener { findNavController().navigate(R.id.action_settingsFragment_to_twibbonFragment) } @@ -59,9 +68,9 @@ class SettingsFragment : Fragment() { val subject = "Comprehensive Account Transaction History Report" val content = """ Attached is a comprehensive report detailing all transactions associated with your account. Should you have any questions or require further assistance, please don't hesitate to reach out. - + Best regards, - + JWR App """.trimIndent() @@ -107,7 +116,8 @@ class SettingsFragment : Fragment() { header.createCell(1).setCellValue("Kategori Transaksi") header.createCell(2).setCellValue("Nominal Transaksi") header.createCell(3).setCellValue("Nama Transaksi") - header.createCell(4).setCellValue("Lokasi") + header.createCell(4).setCellValue("Latitude") + header.createCell(5).setCellValue("Longitude") // Format tanggal val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) @@ -116,10 +126,11 @@ class SettingsFragment : Fragment() { transactions.forEachIndexed { index, transaction -> val row = sheet.createRow(index + 1) row.createCell(0).setCellValue(dateFormat.format(transaction.date)) - row.createCell(1).setCellValue(transaction.category) + row.createCell(1).setCellValue(transaction.category.toString()) row.createCell(2).setCellValue(transaction.amount) row.createCell(3).setCellValue(transaction.title) - row.createCell(4).setCellValue(transaction.location) + row.createCell(4).setCellValue(transaction.latitude) + row.createCell(5).setCellValue(transaction.longitude) } // Menyimpan file diff --git a/app/src/main/java/com/example/pbd_jwr/ui/transaction/TransactionAdapter.kt b/app/src/main/java/com/example/pbd_jwr/ui/transaction/TransactionAdapter.kt index 253d4b27aa4f1213c79520d069f1970bb287bc56..48b30e80e301df3fa505d02eb4ab5cfe8dba7ccb 100644 --- a/app/src/main/java/com/example/pbd_jwr/ui/transaction/TransactionAdapter.kt +++ b/app/src/main/java/com/example/pbd_jwr/ui/transaction/TransactionAdapter.kt @@ -28,7 +28,7 @@ class TransactionAdapter : ListAdapter<Transaction, TransactionAdapter.Transacti fun bind(transaction: Transaction) { with(binding) { textViewTitle.text = transaction.title - textViewCategory.text = transaction.category + textViewCategory.text = transaction.category.toString() textViewAmount.text = transaction.amount.toString() } diff --git a/app/src/main/java/com/example/pbd_jwr/ui/transaction/TransactionAddFragment.kt b/app/src/main/java/com/example/pbd_jwr/ui/transaction/TransactionAddFragment.kt index b65f19daa9527c8f3fbd5565106e17454ba28f99..66c8b15388e0b6598337ad7892c50677c3a15810 100644 --- a/app/src/main/java/com/example/pbd_jwr/ui/transaction/TransactionAddFragment.kt +++ b/app/src/main/java/com/example/pbd_jwr/ui/transaction/TransactionAddFragment.kt @@ -1,19 +1,30 @@ package com.example.pbd_jwr.ui.transaction import android.Manifest +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.content.SharedPreferences +import androidx.localbroadcastmanager.content.LocalBroadcastManager import android.content.pm.PackageManager +import android.os.Build import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.AdapterView +import android.widget.ArrayAdapter import android.widget.Toast +import androidx.annotation.RequiresApi import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModelProvider import androidx.navigation.fragment.findNavController -import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat import com.example.pbd_jwr.data.entity.Transaction +import com.example.pbd_jwr.data.model.Category import com.example.pbd_jwr.databinding.FragmentTransactionAddBinding +import com.example.pbd_jwr.encryptedSharedPref.EncryptedSharedPref import com.google.android.gms.location.FusedLocationProviderClient import com.google.android.gms.location.LocationServices import com.google.android.gms.location.LocationRequest @@ -30,6 +41,9 @@ class TransactionAddFragment : Fragment() { private lateinit var fusedLocationClient: FusedLocationProviderClient + private lateinit var encryptedSharedPref: SharedPreferences + + @RequiresApi(Build.VERSION_CODES.TIRAMISU) override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -40,12 +54,29 @@ class TransactionAddFragment : Fragment() { _binding = FragmentTransactionAddBinding.inflate(inflater, container, false) val root: View = binding.root - // Inisialisasi FusedLocationProviderClient - fusedLocationClient = LocationServices.getFusedLocationProviderClient(requireActivity()) + val filter = IntentFilter(TransactionAddFragment.ACTION_RANDOMIZE_TRANSACTION) + LocalBroadcastManager.getInstance(requireContext()).registerReceiver(randomizeTransactionReceiver, filter) - // Menampilkan lokasi saat ini di EditText + fusedLocationClient = LocationServices.getFusedLocationProviderClient(requireActivity()) showCurrentLocation() + val spinnerCategory = binding.spinnerCategory + val categories = arrayOf(Category.INCOME, Category.EXPENSE) + val adapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_item, categories) + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) + spinnerCategory.adapter = adapter + + spinnerCategory.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { + override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { + val selectedCategory = categories[position] + Toast.makeText(requireContext(), "Selected category: $selectedCategory", Toast.LENGTH_SHORT).show() + } + + override fun onNothingSelected(parent: AdapterView<*>?) { + // Handle jika tidak ada item yang dipilih + } + } + binding.btnSubmit.setOnClickListener { onSubmitClicked() } @@ -54,10 +85,23 @@ class TransactionAddFragment : Fragment() { if (editMode) { val transaction = arguments?.getParcelable<Transaction>("transaction") transaction?.let { + val latitude = it.latitude + val longitude = it.longitude + val latitudeString = "$latitude" + val longitudeString = "$longitude" + binding.editTextTitle.setText(it.title) - binding.editTextCategory.setText(it.category) binding.editTextAmount.setText(it.amount.toString()) - binding.editTextLocation.setText(it.location) + binding.editTextLatitude.setText(latitudeString) + binding.editTextLongitude.setText(longitudeString) + + val category = it.category + if (category != null) { + val categoryIndex = categories.indexOf(category) + if (categoryIndex != -1) { + spinnerCategory.setSelection(categoryIndex) + } + } } } @@ -65,65 +109,54 @@ class TransactionAddFragment : Fragment() { return root } + private fun handleRandomizeTransaction() { + val editMode = arguments?.getBoolean("editMode", false) ?: false + if (!editMode) { + println("random random") + fillRandomField() + } + } + + private val randomizeTransactionReceiver = object : BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + println("Intent diterima oleh broadcast receiver") + if (intent?.action == "com.example.pbd_jwr.RANDOMIZE_TRANSACTION") { + handleRandomizeTransaction() + } + } + } + private fun showCurrentLocation() { if (ContextCompat.checkSelfPermission( requireContext(), Manifest.permission.ACCESS_FINE_LOCATION ) == PackageManager.PERMISSION_GRANTED ) { - println("granted") - // Jika izin diberikan, dapatkan lokasi saat ini fusedLocationClient.lastLocation .addOnSuccessListener { location -> - // Jika lokasi berhasil didapatkan, set nilai EditText lokasi location?.let { val latitude = it.latitude val longitude = it.longitude + val latitudeString = "$latitude" + val longitudeString = "$longitude" val currentLocation = "Latitude: $latitude, Longitude: $longitude" - println(currentLocation) - binding.editTextLocation.setText(currentLocation) + binding.editTextLatitude.setText(latitudeString) + binding.editTextLongitude.setText(longitudeString) } } .addOnFailureListener { e -> - // Jika gagal mendapatkan lokasi, tampilkan pesan kesalahan - println("haha") Toast.makeText( requireContext(), "Failed to get location: ${e.message}", Toast.LENGTH_SHORT ).show() } - - val locationRequest = LocationRequest.create().apply { - priority = LocationRequest.PRIORITY_HIGH_ACCURACY - interval = 10000 // Interval pembaruan lokasi dalam milidetik (contoh: 10 detik) - fastestInterval = 5000 // Interval tercepat untuk pembaruan lokasi dalam milidetik (contoh: 5 detik) - } - - // Meminta pembaruan lokasi secara real-time - fusedLocationClient.requestLocationUpdates( - locationRequest, - object : LocationCallback() { - override fun onLocationResult(locationResult: LocationResult) { - super.onLocationResult(locationResult) - // Mendapatkan lokasi saat ini dari locationResult - val lastLocation = locationResult.lastLocation - val latitude = lastLocation.latitude - val longitude = lastLocation.longitude - val currentLocation = "Latitude: $latitude, Longitude: $longitude" - binding.editTextLocation.setText(currentLocation) - } - }, - null - ) } else { - println("not granted") - // Jika izin lokasi belum diberikan, minta izin - ActivityCompat.requestPermissions( - requireActivity(), - arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), - LOCATION_PERMISSION_REQUEST_CODE - ) + val latitude = "6.8915" + val longitude = "107.6107" + val currentLocation = "Latitude: $latitude, Longitude: $longitude" + binding.editTextLatitude.setText(latitude) + binding.editTextLongitude.setText(longitude) } } @@ -136,10 +169,8 @@ class TransactionAddFragment : Fragment() { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (requestCode == LOCATION_PERMISSION_REQUEST_CODE) { if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - // Izin lokasi diberikan, panggil showCurrentLocation untuk menampilkan lokasi showCurrentLocation() } else { - // Izin lokasi ditolak, tampilkan pesan kesalahan Toast.makeText( requireContext(), "Location permission denied. Some functionality may be limited.", @@ -153,59 +184,80 @@ class TransactionAddFragment : Fragment() { private fun onSubmitClicked() { val title = binding.editTextTitle.text.toString().trim() - val category = binding.editTextCategory.text.toString().trim() val amountString = binding.editTextAmount.text.toString().trim() - val location = binding.editTextLocation.text.toString().trim() + val latitudeString = binding.editTextLatitude.text.toString().trim() // Ambil nilai latitude dari EditText + val longitudeString = binding.editTextLongitude.text.toString().trim() + + val category = binding.spinnerCategory.selectedItem as Category // Validate input fields - if (title.isEmpty() || category.isEmpty() || amountString.isEmpty() || location.isEmpty()) { + if (title.isEmpty() || amountString.isEmpty() || latitudeString.isEmpty() || longitudeString.isEmpty()) { showError("All fields are required") return } + // Validate category + if (category == null) { + showError("Please select a category") + return + } + val amount = amountString.toDoubleOrNull() - if (amount == null || amount <= 0) { - showError("Invalid amount") + val latitude = latitudeString.toDoubleOrNull() + val longitude = longitudeString.toDoubleOrNull() + + if (amount == null || amount <= 0 || latitude == null || longitude == null) { + showError("Invalid amount , latitude, or longitude") return } val date = Date().time + val editMode = arguments?.getBoolean("editMode", false) ?: false + encryptedSharedPref = EncryptedSharedPref.create(requireContext(), "login") + val currentUserEmail = encryptedSharedPref.getString("email", "") ?: "" - val editMode = arguments?.getBoolean("editMode", false) ?: false - println("editMode") - println(editMode) if (editMode) { - // Editing mode val transactionId = arguments?.getLong("transactionId", -1L) ?: -1L - editTransaction(transactionId, title, category, amount, location, date) + editTransaction(transactionId, title, category, amount, latitude, longitude, date, currentUserEmail) findNavController().popBackStack() } else { - // Adding mode - addTransaction(title, category, amount, location, date) + addTransaction(title, category, amount, latitude, longitude, date, currentUserEmail) } findNavController().popBackStack() } - private fun addTransaction(title: String, category: String, amount: Double, location: String, date: Long) { - mTransactionViewModel.addTransaction(Transaction(userId = 1, title = title, category = category, amount = amount, location = location, date = date)) + private fun addTransaction(title: String, category: Category, amount: Double, latitude: Double, longitude: Double, date: Long, email: String) { + mTransactionViewModel.addTransaction(Transaction(title = title, category = category, amount = amount, latitude = latitude, longitude = longitude, date = date, email = email)) } - private fun editTransaction(transactionId: Long, title: String, category: String, amount: Double, location: String, date: Long) { - mTransactionViewModel.updateTransaction(Transaction(transactionId, userId = 1, title = title, category = category, amount = amount, location = location, date = date)) + private fun editTransaction(transactionId: Long, title: String, category: Category, amount: Double, latitude: Double, longitude: Double, date: Long, currentUserEmail: String) { + mTransactionViewModel.updateTransaction(Transaction(id = transactionId, title = title, category = category, amount = amount, latitude = latitude, longitude = longitude, date = date, email = currentUserEmail)) } private fun showError(message: String) { Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show() } + private fun fillRandomField() { + val randomTitle = generateRandomTitle() + binding.editTextTitle.setText(randomTitle) + } + + private fun generateRandomTitle(): String { + return "Random Transaction ${System.currentTimeMillis()}" + } + override fun onDestroyView() { super.onDestroyView() + LocalBroadcastManager.getInstance(requireContext()).unregisterReceiver(randomizeTransactionReceiver) } companion object { private const val LOCATION_PERMISSION_REQUEST_CODE = 1001 + const val ACTION_RANDOMIZE_TRANSACTION = "com.example.pbd_jwr.RANDOMIZE_TRANSACTION" } + } diff --git a/app/src/main/java/com/example/pbd_jwr/ui/transaction/TransactionDetailFragment.kt b/app/src/main/java/com/example/pbd_jwr/ui/transaction/TransactionDetailFragment.kt index 87e55a331c4999fde6d79c1e413a77294d556347..c6fc790375b7510d5839679df3967e15815ccc36 100644 --- a/app/src/main/java/com/example/pbd_jwr/ui/transaction/TransactionDetailFragment.kt +++ b/app/src/main/java/com/example/pbd_jwr/ui/transaction/TransactionDetailFragment.kt @@ -13,14 +13,27 @@ import androidx.navigation.fragment.findNavController import com.example.pbd_jwr.R import com.example.pbd_jwr.data.entity.Transaction import com.example.pbd_jwr.databinding.FragmentTransactionDetailBinding - -class TransactionDetailFragment : Fragment() { +//import com.example.pbd_jwr.ui.map.MapsFragment +import com.google.android.gms.maps.CameraUpdateFactory +import com.google.android.gms.maps.GoogleMap +import com.google.android.gms.maps.OnMapReadyCallback +import com.google.android.gms.maps.SupportMapFragment +import com.google.android.gms.maps.model.LatLng +import com.google.android.gms.maps.model.MarkerOptions +import java.text.SimpleDateFormat +import java.util.Calendar +import java.util.Locale + +class TransactionDetailFragment : Fragment(), OnMapReadyCallback { private var _binding: FragmentTransactionDetailBinding? = null private val binding get() = _binding!! private lateinit var mTransactionViewModel: TransactionViewModel + private lateinit var googleMap: GoogleMap + + private var transaction: Transaction? = null override fun onCreateView( inflater: LayoutInflater, @@ -34,7 +47,6 @@ class TransactionDetailFragment : Fragment() { val transaction = arguments?.getParcelable<Transaction>("transaction") - if (transaction != null) { displayTransactionDetails(transaction) @@ -72,14 +84,43 @@ class TransactionDetailFragment : Fragment() { private fun displayTransactionDetails(transaction: Transaction) { binding.textViewTitle.text = transaction.title - binding.textViewCategory.text = transaction.category + binding.textViewCategory.text = transaction.category.toString() binding.textViewAmount.text = transaction.amount.toString() - binding.textViewLocation.text = transaction.location - binding.textViewDate.text = transaction.date.toString() + binding.textViewLocation.text = "${transaction.latitude.toString()}, ${transaction.longitude.toString()}" + binding.textViewDate.text = formatDate(transaction.date) + + binding.textViewCategoryLabel.text = "Category: " + binding.textViewAmountLabel.text = "Amount: " + binding.textViewLocationLabel.text = "Location: " + binding.textViewDateLabel.text = "Date: " + } + + private fun formatDate(milliseconds: Long): String { + val sdf = SimpleDateFormat("dd MMMM yyyy HH:mm:ss", Locale.getDefault()) + val calendar = Calendar.getInstance() + calendar.timeInMillis = milliseconds + return sdf.format(calendar.time) } private fun deleteTransaction(transaction: Transaction) { mTransactionViewModel.deleteTransaction(transaction) findNavController().popBackStack() } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + val mapFragment = childFragmentManager.findFragmentById(R.id.mapFragment) as SupportMapFragment + mapFragment.getMapAsync(this) + } + + override fun onMapReady(map: GoogleMap) { + googleMap = map + transaction?.let { addMarker(it.latitude, it.longitude) } + } + + private fun addMarker(latitude: Double, longitude: Double) { + val location = LatLng(latitude, longitude) + googleMap.addMarker(MarkerOptions().position(location).title("Transaction Location")) + googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(location, 15f)) + } } diff --git a/app/src/main/java/com/example/pbd_jwr/ui/transaction/TransactionFragment.kt b/app/src/main/java/com/example/pbd_jwr/ui/transaction/TransactionFragment.kt index b75985dc6fb46bbcb8dd080307254424b25e3e5f..2fe780e9c0c0cc726bf440e4a5f062caef810070 100644 --- a/app/src/main/java/com/example/pbd_jwr/ui/transaction/TransactionFragment.kt +++ b/app/src/main/java/com/example/pbd_jwr/ui/transaction/TransactionFragment.kt @@ -1,5 +1,6 @@ package com.example.pbd_jwr.ui.transaction +import android.content.SharedPreferences import android.os.Bundle import android.util.Log import android.view.LayoutInflater @@ -12,6 +13,7 @@ import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.LinearLayoutManager import com.example.pbd_jwr.databinding.FragmentTransactionBinding import com.example.pbd_jwr.R +import com.example.pbd_jwr.encryptedSharedPref.EncryptedSharedPref class TransactionFragment : Fragment() { @@ -21,17 +23,21 @@ class TransactionFragment : Fragment() { private lateinit var mTransactionViewModel: TransactionViewModel private lateinit var transactionAdapter: TransactionAdapter + private lateinit var encryptedSharedPref: SharedPreferences + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { + _binding = FragmentTransactionBinding.inflate(inflater, container, false) val root: View = binding.root mTransactionViewModel = ViewModelProvider(this)[TransactionViewModel::class.java] - + encryptedSharedPref = EncryptedSharedPref.create(requireContext(), "login") + val currentUserEmail = encryptedSharedPref.getString("email", "") ?: "" mTransactionViewModel.getAllTransactions().observe(viewLifecycleOwner, Observer { transactions -> transactions.forEach { transaction -> @@ -50,7 +56,7 @@ class TransactionFragment : Fragment() { findNavController().navigate(R.id.action_transactionFragment_to_transactionAddFragment) } - mTransactionViewModel.getAllTransactions().observe(viewLifecycleOwner, Observer { transactions -> + mTransactionViewModel.getTransactionsByEmail(currentUserEmail).observe(viewLifecycleOwner, Observer { transactions -> transactionAdapter.submitList(transactions) }) diff --git a/app/src/main/java/com/example/pbd_jwr/ui/transaction/TransactionViewModel.kt b/app/src/main/java/com/example/pbd_jwr/ui/transaction/TransactionViewModel.kt index 4c61748cc2d3faf8e9405c369fb04aa41c0008b5..7928d1090c3a0789db9f6cac8669801109b71c7d 100644 --- a/app/src/main/java/com/example/pbd_jwr/ui/transaction/TransactionViewModel.kt +++ b/app/src/main/java/com/example/pbd_jwr/ui/transaction/TransactionViewModel.kt @@ -29,17 +29,17 @@ class TransactionViewModel(application: Application) : AndroidViewModel(applicat return repository.getAllTransactions() } - + fun getTransactionsByEmail(email: String): LiveData<List<Transaction>> { + return repository.getTransactionsByEmail(email) + } fun addTransaction(transaction: Transaction) { viewModelScope.launch(Dispatchers.IO) { try { repository.addTransaction(transaction) _transactionSubmitted.postValue(true) - println("lolos") } catch (e: Exception) { _transactionSubmitted.postValue(false) - println("ga lolos") } } } diff --git a/app/src/main/java/com/example/pbd_jwr/ui/user/UserAdapter.kt b/app/src/main/java/com/example/pbd_jwr/ui/user/UserAdapter.kt deleted file mode 100644 index ece9ee572a8e88b024101526d0db7279a9f1d33f..0000000000000000000000000000000000000000 --- a/app/src/main/java/com/example/pbd_jwr/ui/user/UserAdapter.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.example.pbd_jwr.ui.user - -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TextView -import androidx.recyclerview.widget.RecyclerView -import com.example.pbd_jwr.R -import com.example.pbd_jwr.data.entity.User - -class UserAdapter(private var userList: List<User>) : - RecyclerView.Adapter<UserAdapter.UserViewHolder>() { - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder { - val itemView = LayoutInflater.from(parent.context) - .inflate(R.layout.user_item, parent, false) - return UserViewHolder(itemView) - } - - override fun onBindViewHolder(holder: UserViewHolder, position: Int) { - val currentUser = userList[position] - holder.bind(currentUser) - } - - override fun getItemCount(): Int { - return userList.size - } - - fun updateUserList(newUserList: List<User>) { - userList = newUserList - notifyDataSetChanged() - } - - inner class UserViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - private val fullNameTextView: TextView = itemView.findViewById(R.id.textViewFullName) - private val emailTextView: TextView = itemView.findViewById(R.id.textViewEmail) - - fun bind(user: User) { - fullNameTextView.text = user.fullName - emailTextView.text = user.email - } - } -} diff --git a/app/src/main/java/com/example/pbd_jwr/ui/user/UserFragment.kt b/app/src/main/java/com/example/pbd_jwr/ui/user/UserFragment.kt deleted file mode 100644 index 00df519acfd944e734d9fb810d183453741deb4e..0000000000000000000000000000000000000000 --- a/app/src/main/java/com/example/pbd_jwr/ui/user/UserFragment.kt +++ /dev/null @@ -1,59 +0,0 @@ -package com.example.pbd_jwr.ui.user - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.Fragment -import androidx.lifecycle.Observer -import androidx.lifecycle.ViewModelProvider -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView -import com.example.pbd_jwr.R -import com.example.pbd_jwr.data.entity.User -import com.example.pbd_jwr.data.repository.UserRepository -import com.example.pbd_jwr.databinding.FragmentUserBinding - -class UserFragment(private val userRepository: UserRepository) : Fragment() { - - private lateinit var mUserViewModel: UserViewModel - - private lateinit var userRecyclerView: RecyclerView - private lateinit var userAdapter: UserAdapter - - private var _binding: FragmentUserBinding? = null - - private val binding get() = _binding!! - - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - val view = inflater.inflate(R.layout.fragment_user, container, false) - - // Initialize RecyclerView and adapter - userRecyclerView = view.findViewById(R.id.recyclerViewUsers) - userAdapter = UserAdapter(emptyList()) - - // Set up RecyclerView - userRecyclerView.layoutManager = LinearLayoutManager(requireContext()) - userRecyclerView.adapter = userAdapter - - // Observe LiveData from UserRepository to get user list - userRepository.getAllUsers().observe(viewLifecycleOwner, Observer { userList -> - userAdapter.updateUserList(userList) - }) - -// _binding = FragmentUserBinding.inflate(inflater, container, false) -// -// val view : View = binding.root - - return view - } - - override fun onDestroyView() { - super.onDestroyView() - } -} diff --git a/app/src/main/java/com/example/pbd_jwr/ui/user/UserViewModel.kt b/app/src/main/java/com/example/pbd_jwr/ui/user/UserViewModel.kt deleted file mode 100644 index b4eb543337847bb4137751d50892be0c03c7a84b..0000000000000000000000000000000000000000 --- a/app/src/main/java/com/example/pbd_jwr/ui/user/UserViewModel.kt +++ /dev/null @@ -1,51 +0,0 @@ -package com.example.pbd_jwr.ui.user - -import android.app.Application -import androidx.lifecycle.AndroidViewModel -import androidx.lifecycle.LiveData -import androidx.lifecycle.viewModelScope -import com.example.pbd_jwr.data.database.AppDatabase -import com.example.pbd_jwr.data.entity.User -import com.example.pbd_jwr.data.repository.UserRepository -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch - -class UserViewModel(application: Application) : AndroidViewModel(application) { - - val readAllData: LiveData<List<User>> // Change visibility to public - private val repository: UserRepository - - init { - val userDao = AppDatabase.getDatabase(application).userDao() - repository = UserRepository(userDao) - readAllData = repository.getAllUsers() - - readAllData.observeForever { userList -> - userList?.let { - for (user in userList) { - println("User: ${user.fullName}, ${user.email}") - } - } - } - - // Inside your UserViewModel or wherever readAllData is accessible - val userList: List<User>? = readAllData.value - - - if (userList != null) { - for (user in userList) { - println("User: ${user.fullName}, ${user.email}") - } - } else { - // userList is null, LiveData has not emitted any data yet - println("No data available yet") - } - - } - - fun createUser(user: User) { - viewModelScope.launch(Dispatchers.IO) { - repository.createUser(user) - } - } -} diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml index 79fc9b3783be7f58787292ad55ba0bbeac1fd3b6..eb8b3c50d7902384666d3b95f4913491037f0703 100644 --- a/app/src/main/res/layout/fragment_settings.xml +++ b/app/src/main/res/layout/fragment_settings.xml @@ -46,5 +46,17 @@ app:layout_constraintHorizontal_bias="0.498" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/saveBtn" - app:layout_constraintVertical_bias="0.024" /> + app:layout_constraintVertical_bias="0.024"/> + + <Button + android:id="@+id/randomTransactionBtn" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="RandomizeTransaction" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.497" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_bias="0.233" /> </androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_transaction_add.xml b/app/src/main/res/layout/fragment_transaction_add.xml index a6ef50f2d5911bffe07f25d08aeac2a6da689d64..9acbf35ff3b7fdaf04a55e11415b3363648bdb43 100644 --- a/app/src/main/res/layout/fragment_transaction_add.xml +++ b/app/src/main/res/layout/fragment_transaction_add.xml @@ -1,72 +1,91 @@ <?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" - xmlns:tools="http://schemas.android.com/tools" + android:padding="16dp" tools:context=".MainActivity" - android:padding="16dp"> + tools:layout_editor_absoluteX="0dp" + tools:layout_editor_absoluteY="22dp"> <!-- Back Button --> <Button android:id="@+id/backButton" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:layout_marginStart="16dp" + android:layout_marginTop="16dp" android:background="?attr/selectableItemBackgroundBorderless" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" - android:layout_marginStart="16dp" - android:layout_marginTop="16dp"/> + app:layout_constraintTop_toTopOf="parent" /> <!-- Form Fields --> <EditText android:id="@+id/editTextTitle" android:layout_width="0dp" android:layout_height="wrap_content" + android:layout_marginStart="16dp" + android:layout_marginTop="36dp" + android:layout_marginEnd="16dp" android:hint="Title" - app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintTop_toBottomOf="@id/backButton" - android:layout_marginTop="16dp" - android:layout_marginEnd="16dp" - android:layout_marginStart="16dp"/> + app:layout_constraintHorizontal_bias="0.0" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/backButton" /> - <EditText - android:id="@+id/editTextCategory" + <!-- Location Field --> + + <Spinner + android:id="@+id/spinnerCategory" android:layout_width="0dp" android:layout_height="wrap_content" - android:hint="Category" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintTop_toBottomOf="@id/editTextTitle" - android:layout_marginTop="16dp" + android:layout_marginStart="16dp" + android:layout_marginTop="32dp" android:layout_marginEnd="16dp" - android:layout_marginStart="16dp"/> + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.0" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/editTextTitle" /> <EditText android:id="@+id/editTextAmount" android:layout_width="0dp" android:layout_height="wrap_content" + android:layout_marginStart="16dp" + android:layout_marginTop="28dp" + android:layout_marginEnd="16dp" android:hint="Amount" - app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintTop_toBottomOf="@id/editTextCategory" - android:layout_marginTop="16dp" - android:layout_marginEnd="16dp" - android:layout_marginStart="16dp"/> + app:layout_constraintHorizontal_bias="0.0" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/spinnerCategory" /> - <!-- Location Field --> <EditText - android:id="@+id/editTextLocation" + android:id="@+id/editTextLatitude" android:layout_width="0dp" android:layout_height="wrap_content" - android:hint="Location" - app:layout_constraintStart_toStartOf="parent" + android:layout_marginStart="16dp" + android:layout_marginTop="28dp" + android:layout_marginEnd="16dp" + android:hint="Latitude" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintTop_toBottomOf="@id/editTextAmount" - android:layout_marginTop="16dp" + app:layout_constraintHorizontal_bias="0.0" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/editTextAmount" /> + + <EditText + android:id="@+id/editTextLongitude" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginStart="16dp" + android:layout_marginTop="20dp" android:layout_marginEnd="16dp" - android:layout_marginStart="16dp"/> + android:hint="Longitude" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.0" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/editTextLatitude" /> <!-- Submit Button --> @@ -74,11 +93,12 @@ android:id="@+id/btnSubmit" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:layout_marginEnd="16dp" + android:layout_marginBottom="212dp" android:text="@string/submit" - app:layout_constraintBottom_toBottomOf="@id/editTextLocation" - app:layout_constraintEnd_toEndOf="@id/editTextLocation" - app:layout_constraintStart_toStartOf="@id/editTextLocation" - android:layout_marginTop="16dp" - android:layout_marginEnd="16dp"/> + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="@id/editTextLongitude" + app:layout_constraintHorizontal_bias="0.533" + app:layout_constraintStart_toStartOf="@id/editTextLongitude" /> </androidx.constraintlayout.widget.ConstraintLayout> diff --git a/app/src/main/res/layout/fragment_transaction_detail.xml b/app/src/main/res/layout/fragment_transaction_detail.xml index d8a81388707a4e1e0a96f7acc131ecd4b5ff5ee2..8d3cf514701a814c11f86d094e9bbc35ee32fba9 100644 --- a/app/src/main/res/layout/fragment_transaction_detail.xml +++ b/app/src/main/res/layout/fragment_transaction_detail.xml @@ -1,6 +1,7 @@ <?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" android:padding="16dp"> @@ -9,97 +10,161 @@ android:id="@+id/textViewTitle" android:layout_width="match_parent" android:layout_height="wrap_content" - android:textSize="24sp" - android:textStyle="bold" - android:layout_marginTop="8dp" - app:layout_constraintTop_toBottomOf="@id/btnEdit" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toEndOf="parent" /> + android:layout_marginTop="10dp" + android:textSize="18sp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toBottomOf="@id/textViewTitleLabel" /> <TextView android:id="@+id/textViewCategory" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_marginTop="10dp" android:textSize="18sp" - android:layout_marginTop="8dp" - app:layout_constraintTop_toBottomOf="@id/textViewTitle" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.0" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toEndOf="parent" /> + app:layout_constraintTop_toBottomOf="@id/textViewCategoryLabel" /> <TextView android:id="@+id/textViewAmount" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_marginTop="10dp" android:textSize="18sp" - android:layout_marginTop="8dp" - app:layout_constraintTop_toBottomOf="@id/textViewCategory" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.0" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toEndOf="parent" /> + app:layout_constraintTop_toBottomOf="@id/textViewAmountLabel" /> <TextView android:id="@+id/textViewLocation" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_marginTop="10dp" android:textSize="18sp" - android:layout_marginTop="8dp" - app:layout_constraintTop_toBottomOf="@id/textViewAmount" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.0" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toEndOf="parent" /> + app:layout_constraintTop_toBottomOf="@id/textViewLocationLabel" /> <TextView android:id="@+id/textViewDate" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_marginTop="10dp" + android:textSize="18sp" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.0" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/textViewDateLabel" /> + + <TextView + android:id="@+id/textViewTitleLabel" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="10dp" + android:text="Title:" + android:textSize="18sp" + android:textStyle="bold" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.0" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/btnEdit" /> + + <TextView + android:id="@+id/textViewCategoryLabel" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="10dp" + android:text="Category:" + android:textSize="18sp" + android:textStyle="bold" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.0" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/textViewTitle" /> + + + <TextView + android:id="@+id/textViewAmountLabel" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="10dp" + android:text="Amount:" + android:textSize="18sp" + android:textStyle="bold" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.0" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/textViewCategory" /> + + <TextView + android:id="@+id/textViewLocationLabel" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="4dp" + android:text="Location:" android:textSize="18sp" - android:layout_marginTop="8dp" - app:layout_constraintTop_toBottomOf="@id/textViewLocation" + android:textStyle="bold" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.0" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toEndOf="parent" /> - -<!-- <ImageButton--> -<!-- android:id="@+id/backButton"--> -<!-- android:layout_width="wrap_content"--> -<!-- android:layout_height="wrap_content"--> -<!-- android:src="@drawable/ic_back_arrow"--> -<!-- android:background="?attr/selectableItemBackgroundBorderless"--> -<!-- app:layout_constraintStart_toStartOf="parent"--> -<!-- app:layout_constraintTop_toTopOf="parent"--> -<!-- android:layout_marginStart="16dp"--> -<!-- android:layout_marginTop="16dp"/>--> + app:layout_constraintTop_toBottomOf="@id/textViewAmount" /> + + <TextView + android:id="@+id/textViewDateLabel" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="4dp" + android:text="Category:" + android:textSize="18sp" + android:textStyle="bold" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.0" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/textViewLocation" /> <Button android:id="@+id/btnBack" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:elevation="2dp" android:text="Back" android:textColor="@android:color/black" - android:layout_marginTop="16dp" - android:layout_marginStart="16dp" - android:elevation="2dp"/> + tools:layout_editor_absoluteX="16dp" + tools:layout_editor_absoluteY="16dp" /> <Button android:id="@+id/btnDelete" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:elevation="2dp" android:text="Delete" android:textColor="@android:color/black" - android:layout_marginTop="16dp" - android:layout_marginStart="16dp" - android:elevation="2dp" - app:layout_constraintTop_toBottomOf="@id/btnBack"/> + tools:layout_editor_absoluteX="171dp" + tools:layout_editor_absoluteY="16dp" /> <Button android:id="@+id/btnEdit" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="Edit" - android:textColor="@android:color/black" - android:layout_marginBottom="16dp" - android:layout_marginEnd="16dp" - android:layout_alignParentBottom="true" android:layout_alignParentEnd="true" + android:layout_alignParentBottom="true" android:elevation="2dp" - app:layout_constraintTop_toBottomOf="@id/btnDelete"/> + android:text="Edit" + android:textColor="@android:color/black" + tools:layout_editor_absoluteX="293dp" + tools:layout_editor_absoluteY="16dp" /> + + <fragment + android:id="@+id/mapFragment" + android:name="com.google.android.gms.maps.SupportMapFragment" + android:layout_width="match_parent" + android:layout_height="150dp" + android:layout_marginTop="40dp" + app:layout_constraintTop_toBottomOf="@+id/textViewDate" + tools:layout_editor_absoluteX="16dp" /> </androidx.constraintlayout.widget.ConstraintLayout>