diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 0897082f7512e48e89310db81b5455d997417505..d12ae9e3d99625f732e931852177dfc1c945a9d7 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -15,5 +15,6 @@ <option name="resolveExternalAnnotations" value="false" /> </GradleProjectSettings> </option> + <option name="offlineMode" value="true" /> </component> </project> \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000000000000000000000000000000000000..35eb1ddfbbc029bcab630581847471d7f238ec53 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="VcsDirectoryMappings"> + <mapping directory="" vcs="Git" /> + </component> +</project> \ No newline at end of file diff --git a/app/.idea/.gitignore b/app/.idea/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..26d33521af10bcc7fd8cea344038eaaeb78d0ef5 --- /dev/null +++ b/app/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/app/.idea/gradle.xml b/app/.idea/gradle.xml new file mode 100644 index 0000000000000000000000000000000000000000..89935b50bf331d4dc28570d01689a07355603c07 --- /dev/null +++ b/app/.idea/gradle.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="GradleSettings"> + <option name="linkedExternalProjectsSettings"> + <GradleProjectSettings> + <option name="externalProjectPath" value="$PROJECT_DIR$" /> + <option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" /> + <option name="resolveExternalAnnotations" value="false" /> + </GradleProjectSettings> + </option> + </component> +</project> \ No newline at end of file diff --git a/app/.idea/migrations.xml b/app/.idea/migrations.xml new file mode 100644 index 0000000000000000000000000000000000000000..f8051a6f973e69a86e6f07f1a1c87f17a31c7235 --- /dev/null +++ b/app/.idea/migrations.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="ProjectMigrations"> + <option name="MigrateToGradleLocalJavaHome"> + <set> + <option value="$PROJECT_DIR$" /> + </set> + </option> + </component> +</project> \ No newline at end of file diff --git a/app/.idea/misc.xml b/app/.idea/misc.xml new file mode 100644 index 0000000000000000000000000000000000000000..3040d03eac7808595e6eba1929f2e79d28037e12 --- /dev/null +++ b/app/.idea/misc.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="ExternalStorageConfigurationManager" enabled="true" /> + <component name="ProjectRootManager"> + <output url="file://$PROJECT_DIR$/build/classes" /> + </component> + <component name="ProjectType"> + <option name="id" value="Android" /> + </component> +</project> \ No newline at end of file diff --git a/app/.idea/vcs.xml b/app/.idea/vcs.xml new file mode 100644 index 0000000000000000000000000000000000000000..6c0b8635858dc7ad44b93df54b762707ce49eefc --- /dev/null +++ b/app/.idea/vcs.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="VcsDirectoryMappings"> + <mapping directory="$PROJECT_DIR$/.." vcs="Git" /> + </component> +</project> \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 019d1264550b79c477d85b8b7dbca22dbd473d66..bfffbf216a551ec3777d1e0836f1c78fd32b557f 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -54,4 +54,9 @@ dependencies { testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) + + implementation "androidx.room:room-runtime:2.4.0" + kapt "androidx.room:room-compiler:2.4.0" + implementation "androidx.room:room-ktx:2.4.0" + testImplementation "androidx.room:room-testing:2.4.0" } \ No newline at end of file diff --git a/app/src/.idea/.gitignore b/app/src/.idea/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..26d33521af10bcc7fd8cea344038eaaeb78d0ef5 --- /dev/null +++ b/app/src/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/app/src/.idea/misc.xml b/app/src/.idea/misc.xml new file mode 100644 index 0000000000000000000000000000000000000000..639900d13c6182e452e33a3bd638e70a0146c785 --- /dev/null +++ b/app/src/.idea/misc.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="ProjectRootManager"> + <output url="file://$PROJECT_DIR$/out" /> + </component> +</project> \ No newline at end of file diff --git a/app/src/.idea/modules.xml b/app/src/.idea/modules.xml new file mode 100644 index 0000000000000000000000000000000000000000..403a512731b69f8a2d1422ab3f6e10435ba504e8 --- /dev/null +++ b/app/src/.idea/modules.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="ProjectModuleManager"> + <modules> + <module fileurl="file://$PROJECT_DIR$/androidTest/androidTest.iml" filepath="$PROJECT_DIR$/androidTest/androidTest.iml" /> + <module fileurl="file://$PROJECT_DIR$/main/main.iml" filepath="$PROJECT_DIR$/main/main.iml" /> + <module fileurl="file://$PROJECT_DIR$/.idea/src.iml" filepath="$PROJECT_DIR$/.idea/src.iml" /> + <module fileurl="file://$PROJECT_DIR$/test/test.iml" filepath="$PROJECT_DIR$/test/test.iml" /> + </modules> + </component> +</project> \ No newline at end of file diff --git a/app/src/.idea/vcs.xml b/app/src/.idea/vcs.xml new file mode 100644 index 0000000000000000000000000000000000000000..b2bdec2d71b6a5ce4ae49efc37516809c50e4d5e --- /dev/null +++ b/app/src/.idea/vcs.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="VcsDirectoryMappings"> + <mapping directory="$PROJECT_DIR$/../.." vcs="Git" /> + </component> +</project> \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/AddTransactionActivity.kt b/app/src/main/java/com/example/myapplication/AddTransactionActivity.kt new file mode 100644 index 0000000000000000000000000000000000000000..293d67449f9835c3e09e0feaa55f10f6bea91780 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/AddTransactionActivity.kt @@ -0,0 +1,111 @@ +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import android.widget.Toast +import androidx.lifecycle.ViewModelProvider +import java.util.Date + + +class AddTransactionActivity : AppCompatActivity() { + private lateinit var titleEditText: EditText + private lateinit var nominalEditText: EditText + private lateinit var kategoriEditText: EditText + private lateinit var lokasiEditText: EditText + private lateinit var saveButton: Button + + private lateinit var transactionViewModel: TransactionViewModel + private lateinit var transactionRepository: TransactionRepository + + private var currentLocation: Location? = null + + companion object { + private const val LOCATION_PERMISSION_REQUEST_CODE = 123 + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_add_transaction) + + titleEditText = findViewById(R.id.editTextJudul) + nominalEditText = findViewById(R.id.editTextNominal) + kategoriEditText = findViewById(R.id.editTextKategori) + lokasiEditText = findViewById(R.id.editTextLokasi) + saveButton = findViewById(R.id.buttonSimpan) + + val transactionDao = TransactionDatabase.getInstance(this).transactionDao() + transactionRepository = TransactionRepository(transactionDao) + transactionViewModel = ViewModelProvider(this).get(TransactionViewModel::class.java) + transactionViewModel.initialize(transactionRepository) + + saveButton.setOnClickListener { saveTransaction() } + getLocation() + } + + private fun saveTransaction() { + val title = titleEditText.text.toString().trim() + val nominal = nominalEditText.text.toString().trim() + val kategori = kategoriEditText.text.toString().trim() + val lokasi = lokasiEditText.text.toString().trim() + val tanggal = Date() + + if (title.isEmpty() || nominal.isEmpty() || kategori.isEmpty() || lokasi.isEmpty()) { + Toast.makeText(this, "Isi semua atribut transaksi", Toast.LENGTH_SHORT).show() + return + } + + val transaction = TransactionEntity(title, nominal, kategori, lokasi, tanggal) + transactionViewModel.addTransaction(transaction) + Toast.makeText(this, "Transaksi berhasil ditambahkan", Toast.LENGTH_SHORT).show() + finish() + } + + + private fun saveTransaction() { + val title = titleEditText.text.toString().trim() + val nominal = nominalEditText.text.toString().trim() + val kategori = kategoriEditText.text.toString().trim() + val lokasi = lokasiEditText.text.toString().trim() + val tanggal = Date() + + if (title.isEmpty() || nominal.isEmpty() || kategori.isEmpty() || lokasi.isEmpty()) { + Toast.makeText(this, "Isi semua atribut transaksi", Toast.LENGTH_SHORT).show() + return + } + + val transaction = TransactionEntity(title = title, nominal = nominal, kategori = kategori, lokasi = lokasi, tanggal = tanggal) + val insertedTransactionId = transactionViewModel.addTransaction(transaction) + Toast.makeText(this, "Transaksi berhasil ditambahkan dengan ID $insertedTransactionId", Toast.LENGTH_SHORT).show() + finish() + } + + + @SuppressLint("MissingPermission") + private fun getLocation() { + if (LocationUtils.isLocationPermissionGranted(this)) { + LocationUtils.requestLocationUpdates(this) { location -> + currentLocation = location + lokasiEditText.setText("${location.latitude}, ${location.longitude}") + } + } else { + ActivityCompat.requestPermissions( + this, + arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), + LOCATION_PERMISSION_REQUEST_CODE + ) + } + } + + override fun onRequestPermissionsResult( + requestCode: Int, + permissions: Array<out String>, + grantResults: IntArray + ) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults) + if (requestCode == LOCATION_PERMISSION_REQUEST_CODE) { + if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + getLocation() + } else { + Toast.makeText(this, "Izin akses lokasi ditolak", Toast.LENGTH_SHORT).show() + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/MainActivity.kt b/app/src/main/java/com/example/myapplication/MainActivity.kt index 4d6ef5da340dda102514f278d9206df3c9dda050..d3fe50cd00001d4706a4aef150775211cec72c1d 100644 --- a/app/src/main/java/com/example/myapplication/MainActivity.kt +++ b/app/src/main/java/com/example/myapplication/MainActivity.kt @@ -32,7 +32,7 @@ class MainActivity : AppCompatActivity() { // menu should be considered as top level destinations. val appBarConfiguration = AppBarConfiguration( setOf( - R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications + R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications, R.id.navigation_transactions ) ) setupActionBarWithNavController(navController, appBarConfiguration) diff --git a/app/src/main/java/com/example/myapplication/dao/TransactionDao.kt b/app/src/main/java/com/example/myapplication/dao/TransactionDao.kt new file mode 100644 index 0000000000000000000000000000000000000000..2decc8cc970d559bfbfb9e3e2aaa2dd0357e51db --- /dev/null +++ b/app/src/main/java/com/example/myapplication/dao/TransactionDao.kt @@ -0,0 +1,22 @@ +import androidx.lifecycle.LiveData +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.Query +import androidx.room.Update +import androidx.room.Delete + + +@Dao +interface TransactionDao { + @Insert + suspend fun insertTransaction(transaction: TransactionEntity): Long + + @Query("SELECT * FROM transactionentity") + fun getAllTransactions(): LiveData<List<TransactionEntity>> + + @Update + fun update(transaction: TransactionEntity) + + @Delete + fun delete(transaction: TransactionEntity) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/database/TransactionDatabase.kt b/app/src/main/java/com/example/myapplication/database/TransactionDatabase.kt new file mode 100644 index 0000000000000000000000000000000000000000..77859988bc9425354739e1143091a48f8d9f52c8 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/database/TransactionDatabase.kt @@ -0,0 +1,19 @@ +@Database (entities = [TransactionEntity::class], version = 1) +abstract class TransactionDatabase : RoomDatabase() { + abstract fun transactionDao(): TransactionDao + + companion object { + @Volatile + private var instance: TransactionDatabase? = null + + fun getInstance (context: Context): TransactionDatabase { + return instance ?: synchronized(this) { + instance ?: Room.databaseBuilder( + context.applicationContext, + TransactionDatabase::class.java, + "transaction_database" + ).build().also { instance = it } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/entities/TransactionEntities.kt b/app/src/main/java/com/example/myapplication/entities/TransactionEntities.kt new file mode 100644 index 0000000000000000000000000000000000000000..9455a4eacecef2b155e0cd697e5197c4e19755a7 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/entities/TransactionEntities.kt @@ -0,0 +1,27 @@ +import java.util.Date +import androidx.room.Entity +import androidx.room.PrimaryKey +import androidx.room.ColumnInfo + + +@Entity(tableName = "transactionentity") +data class TransactionEntity( + @PrimaryKey(autoGenerate = true) + @ColumnInfo(name = "id") + val id: Int = 0, + + @ColumnInfo(name = "title") + val title: String, + + @ColumnInfo(name = "nominal") + val nominal: String, + + @ColumnInfo(name = "kategori") + val kategori: String, + + @ColumnInfo(name = "lokasi") + val lokasi: String, + + @ColumnInfo(name = "tanggal") + val tanggal: Date +) \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/repository/TransactionRepository.kt b/app/src/main/java/com/example/myapplication/repository/TransactionRepository.kt new file mode 100644 index 0000000000000000000000000000000000000000..e8d6cd21c293fcb9408206b3a52004b7d657387e --- /dev/null +++ b/app/src/main/java/com/example/myapplication/repository/TransactionRepository.kt @@ -0,0 +1,12 @@ +import androidx.lifecycle.LiveData +import androidx.room.Update +import androidx.room.Delete + + +class TransactionRepository(private val transactionDao: TransactionDao) { + val allTransactions: LiveData<List<TransactionEntity>> = transactionDao.getAllTransactions() + + suspend fun insertTransaction(transaction: TransactionEntity): Long { + return transactionDao.insertTransaction(transaction) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/ui/transaction/TransactionsFragment.kt b/app/src/main/java/com/example/myapplication/ui/transaction/TransactionsFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..f3cd330ccf245752a1b7fed5455e318954a388c4 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/ui/transaction/TransactionsFragment.kt @@ -0,0 +1,45 @@ +package com.example.myapplication.ui.transactions + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.example.myapplication.R +import com.example.myapplication.data.Transaction +import com.example.myapplication.data.TransactionAdapter + +class TransactionsFragment : Fragment() { + + private lateinit var recyclerView: RecyclerView + private lateinit var transactionAdapter: TransactionAdapter + private val transactionList = mutableListOf<Transaction>() + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + val root = inflater.inflate(R.layout.fragment_transactions, container, false) + + recyclerView = root.findViewById(R.id.recyclerViewTransactions) + recyclerView.layoutManager = LinearLayoutManager(requireContext()) + transactionAdapter = TransactionAdapter(transactionList) + recyclerView.adapter = transactionAdapter + + return root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + // Simulate loading transactions from a data source + loadTransactions() + } + + private fun loadTransactions() { + transactionViewModel.allTransactions.observe(viewLifecycleOwner, { transactions -> + transactionList.clear() + transactionList.addAll(transactions.map { Transaction(it.title, it.nominal) }) + transactionAdapter.notifyDataSetChanged() + }) + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_transaction_list.xml b/app/src/main/res/layout/activity_transaction_list.xml new file mode 100644 index 0000000000000000000000000000000000000000..58a86db7217e3717db4a9a2ea76722cf4358f2b8 --- /dev/null +++ b/app/src/main/res/layout/activity_transaction_list.xml @@ -0,0 +1,11 @@ +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + + <androidx.recyclerview.widget.RecyclerView + android:id="@+id/recyclerViewTransactions" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + +</LinearLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/item_transaction.xml b/app/src/main/res/layout/item_transaction.xml new file mode 100644 index 0000000000000000000000000000000000000000..324f70a311f4217786f23aac148585a019bdddf8 --- /dev/null +++ b/app/src/main/res/layout/item_transaction.xml @@ -0,0 +1,38 @@ +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:padding="16dp"> + + <TextView + android:id="@+id/textViewDate" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="16sp" + android:textStyle="bold" /> + + <TextView + android:id="@+id/textViewTitle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="16sp" /> + + <TextView + android:id="@+id/textViewCategory" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="14sp" /> + + <TextView + android:id="@+id/textViewPrice" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="14sp" /> + + <TextView + android:id="@+id/textViewLocation" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="14sp" /> + +</LinearLayout> \ No newline at end of file diff --git a/app/src/main/res/navigation/mobile_navigation.xml b/app/src/main/res/navigation/mobile_navigation.xml index 9439edab38a731e1bd60250d54ab6221c3df626a..f34e15bcc1ff5150d531d9430febc11438fec758 100644 --- a/app/src/main/res/navigation/mobile_navigation.xml +++ b/app/src/main/res/navigation/mobile_navigation.xml @@ -22,4 +22,11 @@ android:name="com.example.myapplication.ui.notifications.NotificationsFragment" android:label="@string/title_notifications" tools:layout="@layout/fragment_notifications" /> + + <fragment + android:id="@+id/navigation_transactions" + android:name="com.example.myapplication.ui.transactions.TransactionsFragment" + android:label="@string/title_transactions" + tools:layout="@layout/fragment_transactions" /> + </navigation> \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 7c90f5c9e23a71dc2bfe8bc20c63727a928e912d..0991321ee1f2559d5010dedc5c81c3d9a2961cfe 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Sat Mar 16 13:51:19 WIB 2024 +#Thu Mar 21 16:32:17 WIB 2024 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists