From 9577630080fc9541a74d8424ebb8382a32df40c1 Mon Sep 17 00:00:00 2001 From: auliamey <auliaannandya@gmail.com> Date: Thu, 4 Apr 2024 20:39:36 +0700 Subject: [PATCH] fix: transaction room and maps --- app/build.gradle.kts | 4 +- .../pbd_jwr/ExampleInstrumentedTest.kt | 2 - app/src/main/AndroidManifest.xml | 13 ++ .../pbd_jwr/converters/CategoryConverter.kt | 20 ++ .../pbd_jwr/data/dao/TransactionDao.kt | 4 + .../com/example/pbd_jwr/data/dao/UserDao.kt | 17 -- .../pbd_jwr/data/database/AppDatabase.kt | 87 ++++----- .../pbd_jwr/data/entity/Transaction.kt | 14 +- .../com/example/pbd_jwr/data/entity/User.kt | 12 -- .../pbd_jwr/data/model/CategoryModel.kt | 6 + .../data/repository/TransactionRepository.kt | 5 + .../pbd_jwr/data/repository/UserRepository.kt | 17 -- .../com/example/pbd_jwr/ui/map/MapFragment.kt | 50 +++++ .../pbd_jwr/ui/settings/SettingsFragment.kt | 21 ++- .../ui/transaction/TransactionAdapter.kt | 2 +- .../ui/transaction/TransactionAddFragment.kt | 174 ++++++++++++------ .../transaction/TransactionDetailFragment.kt | 53 +++++- .../ui/transaction/TransactionFragment.kt | 10 +- .../ui/transaction/TransactionViewModel.kt | 17 +- .../example/pbd_jwr/ui/user/UserAdapter.kt | 43 ----- .../example/pbd_jwr/ui/user/UserFragment.kt | 59 ------ .../example/pbd_jwr/ui/user/UserViewModel.kt | 51 ----- app/src/main/res/layout/fragment_settings.xml | 12 ++ .../res/layout/fragment_transaction_add.xml | 90 +++++---- .../layout/fragment_transaction_detail.xml | 149 ++++++++++----- 25 files changed, 529 insertions(+), 403 deletions(-) create mode 100644 app/src/main/java/com/example/pbd_jwr/converters/CategoryConverter.kt delete mode 100644 app/src/main/java/com/example/pbd_jwr/data/dao/UserDao.kt delete mode 100644 app/src/main/java/com/example/pbd_jwr/data/entity/User.kt create mode 100644 app/src/main/java/com/example/pbd_jwr/data/model/CategoryModel.kt delete mode 100644 app/src/main/java/com/example/pbd_jwr/data/repository/UserRepository.kt create mode 100644 app/src/main/java/com/example/pbd_jwr/ui/map/MapFragment.kt delete mode 100644 app/src/main/java/com/example/pbd_jwr/ui/user/UserAdapter.kt delete mode 100644 app/src/main/java/com/example/pbd_jwr/ui/user/UserFragment.kt delete mode 100644 app/src/main/java/com/example/pbd_jwr/ui/user/UserViewModel.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index a5035dc..d939d90 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -114,7 +114,9 @@ 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") + 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 e547afb..b33e06f 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 c5ac1b1..3c168c3 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/converters/CategoryConverter.kt b/app/src/main/java/com/example/pbd_jwr/converters/CategoryConverter.kt new file mode 100644 index 0000000..93ad6cf --- /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 977a58f..7776329 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 1efeb6d..0000000 --- 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 35cda16..f6bdc6c 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 0e68ab4..415ef33 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 e86d15b..0000000 --- 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 0000000..056b9fe --- /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 8ea9c90..325fbba 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 35b47c2..0000000 --- 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/map/MapFragment.kt b/app/src/main/java/com/example/pbd_jwr/ui/map/MapFragment.kt new file mode 100644 index 0000000..c44e5af --- /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 7bff66d..22c8292 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 @@ -47,15 +48,23 @@ class SettingsFragment : Fragment() { binding.saveBtn.setOnClickListener { saveTransactionsToExcel() } + + val randomizeButton = binding.randomTransactionBtn + randomizeButton.setOnClickListener { + val intent = Intent() + intent.setAction("com.example.pbd_jwr.RANDOMIZE_TRANSACTION") + + LocalBroadcastManager.getInstance(requireContext()).sendBroadcast(intent) + } } private fun sendEmailWithAttachment(toEmail: String?) { 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() @@ -101,7 +110,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()) @@ -110,10 +120,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 253d4b2..48b30e8 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 b65f19d..66c8b15 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 87e55a3..c6fc790 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 b75985d..2fe780e 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 587eb0f..2f60738 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 @@ -1,6 +1,7 @@ package com.example.pbd_jwr.ui.transaction import android.app.Application +import android.util.Log import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData @@ -12,6 +13,7 @@ import com.example.pbd_jwr.data.entity.Transaction import com.example.pbd_jwr.data.repository.TransactionRepository import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import java.util.Locale.Category class TransactionViewModel(application: Application) : AndroidViewModel(application) { @@ -21,23 +23,34 @@ class TransactionViewModel(application: Application) : AndroidViewModel(applicat private val _transactionSubmitted = MutableLiveData<Boolean>() val transactionSubmitted: LiveData<Boolean> = _transactionSubmitted init { + println("masuk init") val transactionDao = AppDatabase.getDatabase(application).transactionDao() repository = TransactionRepository(transactionDao) readAllTransactions = repository.getAllTransactions() + + readAllTransactions.observeForever { transactions -> + // Log the list of transactions whenever it changes + println("All Transactions: $transactions") + } } fun getAllTransactions(): LiveData<List<Transaction>> { return repository.getAllTransactions() } + fun getTransactionsByEmail(email: String): LiveData<List<Transaction>> { + return repository.getTransactionsByEmail(email) + } + fun addTransaction(transaction: Transaction) { +// val transactionWithEmail = transaction.copy(email = email) viewModelScope.launch(Dispatchers.IO) { try { repository.addTransaction(transaction) + println("berhasil") _transactionSubmitted.postValue(true) - println("lolos") } catch (e: Exception) { + println("ga berhasil") _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 ece9ee5..0000000 --- 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 00df519..0000000 --- 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 b4eb543..0000000 --- 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 3e726bb..1ad2cf2 100644 --- a/app/src/main/res/layout/fragment_settings.xml +++ b/app/src/main/res/layout/fragment_settings.xml @@ -34,4 +34,16 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.132" /> + + <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 a6ef50f..9acbf35 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 d8a8138..8d3cf51 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> -- GitLab