Skip to content
Snippets Groups Projects
Commit 07d4b550 authored by Ghazi Akmal Fauzan's avatar Ghazi Akmal Fauzan
Browse files

Merge branch 'feature/location' into 'main'

Feature/location

See merge request NerbFox/if3210-2024-android-nos!9
parents 56ed163f 440b3e61
No related merge requests found
...@@ -2,6 +2,7 @@ plugins { ...@@ -2,6 +2,7 @@ plugins {
id("com.android.application") id("com.android.application")
id("org.jetbrains.kotlin.android") id("org.jetbrains.kotlin.android")
id("kotlin-kapt") id("kotlin-kapt")
id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin")
} }
android { android {
...@@ -50,6 +51,8 @@ dependencies { ...@@ -50,6 +51,8 @@ dependencies {
implementation("com.github.PhilJay:MPAndroidChart:v3.1.0") implementation("com.github.PhilJay:MPAndroidChart:v3.1.0")
implementation("com.google.android.material:material:1.11.0") implementation("com.google.android.material:material:1.11.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4") implementation("androidx.constraintlayout:constraintlayout:2.1.4")
implementation("com.google.android.gms:play-services-maps:18.2.0")
implementation("com.google.android.gms:play-services-location:21.2.0")
testImplementation("junit:junit:4.13.2") testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5") androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
......
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
...@@ -12,6 +13,15 @@ ...@@ -12,6 +13,15 @@
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.NerbOS"> android:theme="@style/Theme.NerbOS">
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="AIzaSyBdVOQUHGOg7TS74kPCzoEtDDlGGZHpAEs" />
<activity
android:name=".MapsActivity"
android:exported="false"
android:label="@string/title_activity_maps" />
<service android:name=".service.NetworkManagerService" /> <service android:name=".service.NetworkManagerService" />
<service <service
......
package com.example.nerbos
import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Camera
import android.location.Address
import android.location.Geocoder
import android.location.Location
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.core.app.ActivityCompat
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 com.example.nerbos.databinding.ActivityMapsBinding
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationServices
import com.google.android.gms.maps.model.Marker
import java.util.Locale
class MapsActivity : AppCompatActivity(), OnMapReadyCallback {
private lateinit var mMap: GoogleMap
private lateinit var binding: ActivityMapsBinding
private lateinit var location: Address
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMapsBinding.inflate(layoutInflater)
setContentView(binding.root)
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
val mapFragment = supportFragmentManager
.findFragmentById(R.id.map) as SupportMapFragment
mapFragment.getMapAsync(this)
val myIntent = intent
val locationName : String? = myIntent.getStringExtra("locationName")
val geocoder = Geocoder(this, Locale.getDefault())
val address = geocoder.getFromLocationName(locationName!!, 1)
if (address != null) {
location = address[0]
}
// Navigation
findViewById<ImageView>(R.id.backButton).setOnClickListener {
val mainIntent: Intent = Intent(this, MainActivity::class.java)
startActivity(mainIntent)
finish()
}
}
override fun onMapReady(googleMap: GoogleMap) {
mMap = googleMap
mMap.uiSettings.isZoomControlsEnabled = true
val currentLatLong : LatLng = LatLng(location.latitude,location.longitude)
val markerOptions = MarkerOptions().position(currentLatLong).title("Current Location")
mMap.addMarker(markerOptions)
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(currentLatLong, 15f))
}
}
\ No newline at end of file
...@@ -19,6 +19,7 @@ class TransactionAdapter() : RecyclerView.Adapter<TransactionAdapter.Transaction ...@@ -19,6 +19,7 @@ class TransactionAdapter() : RecyclerView.Adapter<TransactionAdapter.Transaction
// Create ViewHolder Class // Create ViewHolder Class
private var transactionList : List<Transaction> = emptyList<Transaction>() private var transactionList : List<Transaction> = emptyList<Transaction>()
var onItemClick: ((Transaction) -> Unit)? = null var onItemClick: ((Transaction) -> Unit)? = null
var onLocationClick: ((String) -> Unit)? = null
class TransactionViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){ class TransactionViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
val name: TextView = itemView.findViewById(R.id.transactionName) val name: TextView = itemView.findViewById(R.id.transactionName)
val date: TextView = itemView.findViewById(R.id.transactionDate) val date: TextView = itemView.findViewById(R.id.transactionDate)
...@@ -54,6 +55,10 @@ class TransactionAdapter() : RecyclerView.Adapter<TransactionAdapter.Transaction ...@@ -54,6 +55,10 @@ class TransactionAdapter() : RecyclerView.Adapter<TransactionAdapter.Transaction
holder.itemView.setOnClickListener{ holder.itemView.setOnClickListener{
onItemClick?.invoke(transactionList[position]) onItemClick?.invoke(transactionList[position])
} }
holder.location.setOnClickListener {
onLocationClick?.invoke(holder.location.text.toString())
}
} }
@SuppressLint("NotifyDataSetChanged") @SuppressLint("NotifyDataSetChanged")
fun setData(transactions: List<Transaction>){ fun setData(transactions: List<Transaction>){
......
package com.example.nerbos.fragments.transaction package com.example.nerbos.fragments.transaction
import android.Manifest
import android.app.AlertDialog import android.app.AlertDialog
import android.app.Dialog import android.app.Dialog
import android.content.Intent
import android.content.pm.PackageManager
import android.location.Address
import android.location.Geocoder
import android.location.Location
import android.os.Bundle import android.os.Bundle
import android.text.TextUtils import android.text.TextUtils
import android.util.Log import android.util.Log
...@@ -17,17 +23,24 @@ import android.widget.RadioButton ...@@ -17,17 +23,24 @@ import android.widget.RadioButton
import android.widget.RadioGroup import android.widget.RadioGroup
import android.widget.TextView import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.core.app.ActivityCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.example.nerbos.MapsActivity
import com.example.nerbos.R import com.example.nerbos.R
import com.example.nerbos.model.Transaction import com.example.nerbos.model.Transaction
import com.example.nerbos.model.TransactionCategory import com.example.nerbos.model.TransactionCategory
import com.example.nerbos.viewmodel.TransactionViewModel import com.example.nerbos.viewmodel.TransactionViewModel
import com.example.nerbos.service.Authentication import com.example.nerbos.service.Authentication
import com.example.nerbos.service.Utils import com.example.nerbos.service.Utils
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationServices
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.model.LatLng
import java.util.Locale
// TODO: Rename parameter arguments, choose names that match // TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
...@@ -45,6 +58,10 @@ class TransactionFragment : Fragment() { ...@@ -45,6 +58,10 @@ class TransactionFragment : Fragment() {
private var param2: String? = null private var param2: String? = null
private lateinit var transactionViewModel: TransactionViewModel private lateinit var transactionViewModel: TransactionViewModel
private lateinit var authentication: Authentication private lateinit var authentication: Authentication
private var currentLocation: Location? = null
private lateinit var fusedLocationProviderClient: FusedLocationProviderClient
private lateinit var geocoder: Geocoder
private val permissionCode = 1
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
...@@ -52,6 +69,8 @@ class TransactionFragment : Fragment() { ...@@ -52,6 +69,8 @@ class TransactionFragment : Fragment() {
param1 = it.getString(ARG_PARAM1) param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2) param2 = it.getString(ARG_PARAM2)
} }
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(requireContext())
geocoder = Geocoder(requireContext(), Locale.getDefault())
} }
override fun onCreateView( override fun onCreateView(
...@@ -67,6 +86,7 @@ class TransactionFragment : Fragment() { ...@@ -67,6 +86,7 @@ class TransactionFragment : Fragment() {
recyclerView.layoutManager = LinearLayoutManager(context) recyclerView.layoutManager = LinearLayoutManager(context)
recyclerView.adapter = transactionAdapter recyclerView.adapter = transactionAdapter
transactionAdapter.onItemClick = { transaction -> showModifyTransactionDialog(transaction)} transactionAdapter.onItemClick = { transaction -> showModifyTransactionDialog(transaction)}
transactionAdapter.onLocationClick = {location -> showLocationOnMap(location)}
// Transaction View Model // Transaction View Model
transactionViewModel = ViewModelProvider(this)[TransactionViewModel::class.java] transactionViewModel = ViewModelProvider(this)[TransactionViewModel::class.java]
...@@ -82,6 +102,12 @@ class TransactionFragment : Fragment() { ...@@ -82,6 +102,12 @@ class TransactionFragment : Fragment() {
return view return view
} }
private fun showLocationOnMap(location: String) {
val mapIntent = Intent(requireActivity(), MapsActivity::class.java)
mapIntent.putExtra("locationName", location)
startActivity(mapIntent)
}
private fun showAddTransactionDialog() { private fun showAddTransactionDialog() {
val dialog = Dialog(requireContext()) val dialog = Dialog(requireContext())
...@@ -102,6 +128,14 @@ class TransactionFragment : Fragment() { ...@@ -102,6 +128,14 @@ class TransactionFragment : Fragment() {
dialog.dismiss() dialog.dismiss()
} }
dialog.findViewById<EditText>(R.id.locationInput).setOnClickListener {
// TODO: Buat percabangan kalau ada internet
if (true){
val etLocation= dialog.findViewById<EditText>(R.id.locationInput)
etLocation.setText(getAddressName())
}
}
dialog.show() dialog.show()
dialog.window!!.setBackgroundDrawableResource(R.drawable.round_corner_transparent) dialog.window!!.setBackgroundDrawableResource(R.drawable.round_corner_transparent)
dialog.window!!.attributes = layoutParams dialog.window!!.attributes = layoutParams
...@@ -214,6 +248,36 @@ class TransactionFragment : Fragment() { ...@@ -214,6 +248,36 @@ class TransactionFragment : Fragment() {
} }
} }
private fun setLocation(){
if (ActivityCompat.checkSelfPermission(
requireContext(),
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
requireContext(),
Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(requireActivity(), arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION), permissionCode)
return
}
fusedLocationProviderClient.lastLocation.addOnSuccessListener (requireActivity()){
location ->
currentLocation = location
}
}
private fun getAddressName() : String{
// Hanya set otomatis jika mendapatkan permission, jika tidak input lokasi string
setLocation()
return if (currentLocation!=null){
// Geocode to get the address string
val address = geocoder.getFromLocation(currentLocation!!.latitude, currentLocation!!.longitude, 1)
address!![0].getAddressLine(0)
} else {
""
}
}
private fun inputCheck(name: String, nominal:Float, location:String): Boolean { private fun inputCheck(name: String, nominal:Float, location:String): Boolean {
return !(TextUtils.isEmpty(name) || TextUtils.isEmpty(location) || (nominal<0) ) return !(TextUtils.isEmpty(name) || TextUtils.isEmpty(location) || (nominal<0) )
} }
......
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true" android:height="24dp" android:tint="#FFFFFF" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M11.67,3.87L9.9,2.1 0,12l9.9,9.9 1.77,-1.77L3.54,12z"/>
</vector>
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MapsActivity"
>
<fragment
xmlns:map="http://schemas.android.com/apk/res-auto"
android:id="@+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
map:layout_constraintTop_toTopOf="parent"
/>
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="24sp"
android:textColor="@color/white"
android:background="@color/base_bg"
android:text="@string/maps"
android:paddingTop = "5dp"
android:paddingStart="40dp"
android:paddingEnd="10dp"
android:paddingBottom="10dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="@id/backButton"
/>
<ImageView
android:id="@+id/backButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:paddingBottom="5dp"
android:src="@drawable/ic_back"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
...@@ -46,6 +46,8 @@ ...@@ -46,6 +46,8 @@
<string name="delete_success">Transaction successfully deleted</string> <string name="delete_success">Transaction successfully deleted</string>
<string name="income">Income</string> <string name="income">Income</string>
<string name="outcome">Outcome</string> <string name="outcome">Outcome</string>
<string name="title_activity_maps">MapsActivity</string>
<string name="maps">Maps</string>
<string name="network_sensing_string">No Internet Connection Please check your connection and try again.</string> <string name="network_sensing_string">No Internet Connection Please check your connection and try again.</string>
<string name="close_button">Close Button</string> <string name="close_button">Close Button</string>
<string name="pie_chart">Pie Chart</string> <string name="pie_chart">Pie Chart</string>
......
...@@ -2,4 +2,5 @@ ...@@ -2,4 +2,5 @@
plugins { plugins {
id("com.android.application") version "8.3.1" apply false id("com.android.application") version "8.3.1" apply false
id("org.jetbrains.kotlin.android") version "1.9.22" apply false id("org.jetbrains.kotlin.android") version "1.9.22" apply false
id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin") version "2.0.1" apply false
} }
\ No newline at end of file
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment