From 1c769ea02c51f709382c70c096184ab090cfa123 Mon Sep 17 00:00:00 2001 From: lmj0011 <9396189+lmj0011@users.noreply.github.com> Date: Sun, 5 Dec 2021 00:49:31 -0600 Subject: [PATCH] implement adding a waypoint to building and unit map markers --- app/build.gradle.kts | 2 +- app/deps.list.txt | 10 +- .../courierlocker/database/Building.kt | 9 +- .../courierlocker/database/BuildingUnit.kt | 10 +- .../fragments/EditAptBuildingsMapFragment.kt | 177 +++++++++++++++--- .../fragments/EditAptUnitsMapFragment.kt | 151 ++++++++++++++- .../BottomSheetAptBuildingDetailsFragment.kt | 46 ++++- .../BottomSheetAptUnitDetailsFragment.kt | 47 +++-- .../helpers/AppDataImportExportHelper.kt | 10 +- .../lmj0011/courierlocker/helpers/Const.kt | 3 + .../lmj0011/courierlocker/helpers/Util.kt | 38 ++++ .../ic_baseline_add_location_alt_24.xml | 4 + .../ic_baseline_wrong_location_24.xml | 5 + ...tomsheet_fragment_apt_building_details.xml | 26 +++ .../bottomsheet_fragment_apt_unit_details.xml | 26 +++ .../fragment_edit_apt_buildings_map.xml | 67 +++++-- .../layout/fragment_edit_apt_units_map.xml | 46 ++++- build.gradle.kts | 2 +- 18 files changed, 602 insertions(+), 77 deletions(-) create mode 100644 app/src/main/res/drawable/ic_baseline_add_location_alt_24.xml create mode 100644 app/src/main/res/drawable/ic_baseline_wrong_location_24.xml diff --git a/app/build.gradle.kts b/app/build.gradle.kts index b427c6c..d74a2a4 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -35,7 +35,7 @@ android { applicationId = "name.lmj0011.courierlocker" minSdk = 26 targetSdk = 31 - versionCode = 103 + versionCode = 105 versionName = "2.3.0-beta02" vectorDrawables { diff --git a/app/deps.list.txt b/app/deps.list.txt index fb444ce..048958e 100644 --- a/app/deps.list.txt +++ b/app/deps.list.txt @@ -1,9 +1,9 @@ # auto-generated; this file should be checked into version control -androidx.databinding:viewbinding:7.0.2 -androidx.databinding:databinding-common:7.0.2 -androidx.databinding:databinding-runtime:7.0.2 -androidx.databinding:databinding-adapters:7.0.2 -androidx.databinding:databinding-ktx:7.0.2 +androidx.databinding:viewbinding:7.0.3 +androidx.databinding:databinding-common:7.0.3 +androidx.databinding:databinding-runtime:7.0.3 +androidx.databinding:databinding-adapters:7.0.3 +androidx.databinding:databinding-ktx:7.0.3 org.jetbrains.kotlin:kotlin-parcelize-runtime:1.5.10 org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.10 androidx.navigation:navigation-fragment-ktx:2.3.5 diff --git a/app/src/main/java/name/lmj0011/courierlocker/database/Building.kt b/app/src/main/java/name/lmj0011/courierlocker/database/Building.kt index 7fbe0de..35f586c 100644 --- a/app/src/main/java/name/lmj0011/courierlocker/database/Building.kt +++ b/app/src/main/java/name/lmj0011/courierlocker/database/Building.kt @@ -1,4 +1,11 @@ package name.lmj0011.courierlocker.database -data class Building(val number: String, val latitude: Double, val longitude: Double) \ No newline at end of file +data class Building( + var number: String = "", + var latitude: Double = 0.0, + var longitude: Double = 0.0, + var hasWaypoint: Boolean = false, + var waypointLatitude: Double = 0.0, + var waypointLongitude: Double = 0.0 +) \ No newline at end of file diff --git a/app/src/main/java/name/lmj0011/courierlocker/database/BuildingUnit.kt b/app/src/main/java/name/lmj0011/courierlocker/database/BuildingUnit.kt index ba0621c..0c4862e 100644 --- a/app/src/main/java/name/lmj0011/courierlocker/database/BuildingUnit.kt +++ b/app/src/main/java/name/lmj0011/courierlocker/database/BuildingUnit.kt @@ -1,4 +1,12 @@ package name.lmj0011.courierlocker.database -data class BuildingUnit(var number: String, var floorNumber: String, val latitude: Double, val longitude: Double) \ No newline at end of file +data class BuildingUnit( + var number: String = "", + var floorNumber: String = "", + val latitude: Double = 0.0, + val longitude: Double = 0.0, + var hasWaypoint: Boolean = false, + var waypointLatitude: Double = 0.0, + var waypointLongitude: Double = 0.0 +) \ No newline at end of file diff --git a/app/src/main/java/name/lmj0011/courierlocker/fragments/EditAptBuildingsMapFragment.kt b/app/src/main/java/name/lmj0011/courierlocker/fragments/EditAptBuildingsMapFragment.kt index 5604789..5e33e40 100644 --- a/app/src/main/java/name/lmj0011/courierlocker/fragments/EditAptBuildingsMapFragment.kt +++ b/app/src/main/java/name/lmj0011/courierlocker/fragments/EditAptBuildingsMapFragment.kt @@ -32,9 +32,8 @@ import name.lmj0011.courierlocker.databinding.FragmentCreateOrEditApartmentMapBi import name.lmj0011.courierlocker.databinding.FragmentEditAptBuildingsMapBinding import name.lmj0011.courierlocker.factories.ApartmentViewModelFactory import name.lmj0011.courierlocker.fragments.bottomsheets.BottomSheetAptBuildingDetailsFragment -import name.lmj0011.courierlocker.helpers.AptBldgClusterItem -import name.lmj0011.courierlocker.helpers.PreferenceHelper -import name.lmj0011.courierlocker.helpers.launchUI +import name.lmj0011.courierlocker.helpers.* +import name.lmj0011.courierlocker.helpers.Util.stylePolyline import name.lmj0011.courierlocker.viewmodels.ApartmentViewModel import org.kodein.di.instance import java.lang.Exception @@ -58,8 +57,10 @@ class EditAptBuildingsMapFragment : Fragment(){ private lateinit var args: EditAptBuildingsMapFragmentArgs private var selectedApt = MutableLiveData() private var selectedBldg: Building? = null + private var activePolylinePairList: MutableList?> = mutableListOf() private var fragmentJob = Job() private val uiScope = CoroutineScope(Dispatchers.Main + fragmentJob) + private var selectionMode = Const.BUILDING_SELECTION_MODE @SuppressLint("MissingPermission") override fun onCreateView( @@ -137,28 +138,74 @@ class EditAptBuildingsMapFragment : Fragment(){ gMap.setOnMarkerClickListener(clusterManager) gMap.setOnMapClickListener { + selectionMode = Const.BUILDING_SELECTION_MODE // default mode + this.hideAddBuildingUI() + this.hideAddWaypointUI() } gMap.setOnMapLongClickListener { pinDropMarker.position = it pinDropMarker.isVisible = true - selectedBldg = Building("", it.latitude, it.longitude) - this.showAddBuildingUI() + clearPolylines() + + when(selectionMode) { + Const.BUILDING_SELECTION_MODE -> { + selectedBldg = Building("", it.latitude, it.longitude) + this.showAddBuildingUI() + } + Const.WAYPOINT_SELECTION_MODE -> { + this.showAddWaypointUI() + binding.saveWaypointButton.isEnabled = true + + selectedBldg?.let { bldg -> + bldg.waypointLatitude = it.latitude + bldg.waypointLongitude = it.longitude + drawBldgPolyline(bldg) + } + } + } } clusterManager.setOnClusterItemClickListener { selectedBldg = it.bldg pinDropMarker.isVisible = false - val bottomSheet = BottomSheetAptBuildingDetailsFragment(it.bldg) { + val bottomSheet = BottomSheetAptBuildingDetailsFragment( + building = it.bldg, + addWaypointCallback = { + selectionMode = Const.WAYPOINT_SELECTION_MODE + this.showAddWaypointUI() + binding.saveWaypointButton.isEnabled = false + }, + removeWaypointCallback = { + val oldBldg = selectedBldg!! + + val newBldg = Building( + number = oldBldg.number, + latitude = oldBldg.latitude, + longitude = oldBldg.longitude, + hasWaypoint = false, + ) + + selectedApt.value?.let { apt -> + apt.buildings.remove(oldBldg) + apt.buildings.add(newBldg) + + launchIO { + apartmentViewModel.updateApartment(apt) + selectedApt.postValue(apt) + } + } + }, + removeBuildingCallback = { val builder = MaterialAlertDialogBuilder(requireContext()) builder .setTitle("Building ${it.bldg.number}") .setMessage("Remove this building?") .setPositiveButton("Yes") { _, _ -> - selectedBldg?.let{ selectedApt.value!!.buildings.remove(it) } + selectedBldg?.let{ bldg -> selectedApt.value!!.buildings.remove(bldg) } launchUI { withContext(Dispatchers.IO) { apartmentViewModel.updateApartment(selectedApt.value) @@ -171,7 +218,13 @@ class EditAptBuildingsMapFragment : Fragment(){ } builder.show() - } + }, + dismissCallback = { + clearPolylines() + } + ) + + if (it.bldg.hasWaypoint) drawBldgPolyline(it.bldg) bottomSheet .show(childFragmentManager, "BottomSheetAptBuildingDetailsFragment") @@ -205,25 +258,47 @@ class EditAptBuildingsMapFragment : Fragment(){ } binding.addButton.setOnClickListener { - uiScope.launch { - val b = Building( - binding.buildingEditText.text.toString(), - pinDropMarker.position.latitude, - pinDropMarker.position.longitude - ) + val b = Building( + binding.buildingEditText.text.toString(), + pinDropMarker.position.latitude, + pinDropMarker.position.longitude + ) - selectedBldg = b + selectedBldg = b - selectedApt.value?.let { apt -> - apt.buildings.add(b) + selectedApt.value?.let { apt -> + apt.buildings.add(b) - withContext(Dispatchers.IO) { - apartmentViewModel.updateApartment(apt) - selectedApt.postValue(apt) - } + launchIO { + apartmentViewModel.updateApartment(apt) + selectedApt.postValue(apt) } + } + + mainActivity.hideKeyBoard(binding.buildingEditText) + } + + binding.saveWaypointButton.setOnClickListener { + val oldBldg = selectedBldg!! + + val newBldg = Building( + number = oldBldg.number, + latitude = oldBldg.latitude, + longitude = oldBldg.longitude, + hasWaypoint = true, + waypointLatitude = pinDropMarker.position.latitude, + waypointLongitude = pinDropMarker.position.longitude - mainActivity.hideKeyBoard(binding.buildingEditText) + ) + + selectedApt.value?.let { apt -> + apt.buildings.remove(oldBldg) + apt.buildings.add(newBldg) + + launchIO { + apartmentViewModel.updateApartment(apt) + selectedApt.postValue(apt) + } } } @@ -328,6 +403,30 @@ class EditAptBuildingsMapFragment : Fragment(){ } } this.hideAddBuildingUI() + this.hideAddWaypointUI() + } + + private fun drawBldgPolyline(bldg: Building) { + val polyline = gMap.addPolyline( + PolylineOptions() + .clickable(false) + .add( + LatLng(bldg.waypointLatitude, bldg.waypointLongitude), + LatLng(bldg.latitude, bldg.longitude) + ) + ) + + val pair = stylePolyline(gMap, polyline) + activePolylinePairList.add(pair) + } + + private fun clearPolylines() { + activePolylinePairList.forEach { pair -> + pair?.first?.remove() + pair?.second?.remove() + } + + activePolylinePairList.clear() } private fun hideAddBuildingUI() { @@ -362,5 +461,39 @@ class EditAptBuildingsMapFragment : Fragment(){ binding.buildingEditText.requestFocus() mainActivity.showKeyBoard(binding.buildingEditText) binding.buildingEditText.isEnabled = true + + hideAddWaypointUI() + } + + private fun hideAddWaypointUI() { + val transition = Slide(Gravity.TOP) + transition.duration = 50 + transition.addTarget(binding.addWaypointInputView) + transition.addTarget(binding.saveWaypointButton) + transition.addTarget(binding.addWaypointTextView) + + TransitionManager.beginDelayedTransition(binding.editAptBuildingsMapContainer, transition) + binding.addWaypointInputView.visibility = View.GONE + binding.saveWaypointButton.visibility = View.GONE + binding.addWaypointTextView.visibility = View.GONE + + pinDropMarker.isVisible = false + clearPolylines() + + } + + private fun showAddWaypointUI() { + val transition = Slide(Gravity.TOP) + transition.duration = 50 + transition.addTarget(binding.addWaypointInputView) + transition.addTarget(binding.saveWaypointButton) + transition.addTarget(binding.addWaypointTextView) + + TransitionManager.beginDelayedTransition(binding.editAptBuildingsMapContainer, transition) + binding.addWaypointInputView.visibility = View.VISIBLE + binding.saveWaypointButton.visibility = View.VISIBLE + binding.addWaypointTextView.visibility = View.VISIBLE + + hideAddBuildingUI() } } diff --git a/app/src/main/java/name/lmj0011/courierlocker/fragments/EditAptUnitsMapFragment.kt b/app/src/main/java/name/lmj0011/courierlocker/fragments/EditAptUnitsMapFragment.kt index de952bc..75fc2bb 100644 --- a/app/src/main/java/name/lmj0011/courierlocker/fragments/EditAptUnitsMapFragment.kt +++ b/app/src/main/java/name/lmj0011/courierlocker/fragments/EditAptUnitsMapFragment.kt @@ -2,8 +2,6 @@ package name.lmj0011.courierlocker.fragments import android.annotation.SuppressLint -import android.content.Intent -import android.net.Uri import android.os.Bundle import android.text.InputType import android.view.* @@ -23,7 +21,6 @@ import com.google.android.libraries.maps.CameraUpdateFactory import com.google.android.libraries.maps.GoogleMap import com.google.android.libraries.maps.SupportMapFragment import com.google.android.libraries.maps.model.* -import com.google.android.material.button.MaterialButton import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.maps.android.clustering.ClusterManager import com.google.maps.android.clustering.view.DefaultClusterRenderer @@ -33,7 +30,6 @@ import name.lmj0011.courierlocker.CourierLockerApplication import name.lmj0011.courierlocker.MainActivity import name.lmj0011.courierlocker.R import name.lmj0011.courierlocker.database.Apartment -import name.lmj0011.courierlocker.database.Building import name.lmj0011.courierlocker.database.BuildingUnit import name.lmj0011.courierlocker.database.CourierLockerDatabase import name.lmj0011.courierlocker.databinding.FragmentCreateOrEditApartmentMapBinding @@ -41,10 +37,7 @@ import name.lmj0011.courierlocker.databinding.FragmentEditAptUnitsMapBinding import name.lmj0011.courierlocker.factories.ApartmentViewModelFactory import name.lmj0011.courierlocker.fragments.bottomsheets.BottomSheetAptUnitDetailsFragment import name.lmj0011.courierlocker.fragments.bottomsheets.BottomSheetAptUnitFloorOptionsFragment -import name.lmj0011.courierlocker.helpers.AptBldgClusterItem -import name.lmj0011.courierlocker.helpers.AptBldgUnitClusterItem -import name.lmj0011.courierlocker.helpers.PreferenceHelper -import name.lmj0011.courierlocker.helpers.launchUI +import name.lmj0011.courierlocker.helpers.* import name.lmj0011.courierlocker.viewmodels.ApartmentViewModel import org.kodein.di.instance import timber.log.Timber @@ -69,8 +62,10 @@ class EditAptUnitsMapFragment : Fragment(){ private lateinit var args: EditAptUnitsMapFragmentArgs private var selectedApt = MutableLiveData() private var selectedBldgUnit: BuildingUnit? = null + private var activePolylinePairList: MutableList?> = mutableListOf() private var fragmentJob = Job() private val uiScope = CoroutineScope(Dispatchers.Main + fragmentJob) + private var selectionMode = Const.BUILDING_UNIT_SELECTION_MODE @SuppressLint("MissingPermission") override fun onCreateView( @@ -154,13 +149,30 @@ class EditAptUnitsMapFragment : Fragment(){ gMap.setOnMapClickListener { this.hideAddUnitUI() + this.hideAddWaypointUI() } gMap.setOnMapLongClickListener { pinDropMarker.position = it pinDropMarker.isVisible = true - selectedBldgUnit = BuildingUnit("", "", it.latitude, it.longitude) - this.showAddUnitUI() + clearPolylines() + + when(selectionMode) { + Const.BUILDING_UNIT_SELECTION_MODE -> { + selectedBldgUnit = BuildingUnit("", "", it.latitude, it.longitude) + this.showAddUnitUI() + } + Const.WAYPOINT_SELECTION_MODE -> { + this.showAddWaypointUI() + binding.saveWaypointButton.isEnabled = true + + selectedBldgUnit?.let { unit -> + unit.waypointLatitude = it.latitude + unit.waypointLongitude = it.longitude + drawBldgUnitPolyline(unit) + } + } + } } clusterManager.setOnClusterItemClickListener { @@ -211,6 +223,32 @@ class EditAptUnitsMapFragment : Fragment(){ (requireActivity() as MainActivity).showKeyBoard(inputEditTextField) }, 100) }, + addWaypointCallback = { + selectionMode = Const.WAYPOINT_SELECTION_MODE + this.showAddWaypointUI() + binding.saveWaypointButton.isEnabled = false + }, + removeWaypointCallback = { + val oldUnit = selectedBldgUnit!! + + val newUnit = BuildingUnit( + number = oldUnit.number, + floorNumber = oldUnit.floorNumber, + latitude = oldUnit.latitude, + longitude = oldUnit.longitude, + hasWaypoint = false, + ) + + selectedApt.value?.let { apt -> + apt.buildingUnits.remove(oldUnit) + apt.buildingUnits.add(newUnit) + + launchIO { + apartmentViewModel.updateApartment(apt) + selectedApt.postValue(apt) + } + } + }, removeBuildingUnitCallback = { val builder = MaterialAlertDialogBuilder(requireContext()) @@ -231,9 +269,14 @@ class EditAptUnitsMapFragment : Fragment(){ } builder.show() + }, + dismissCallback = { + clearPolylines() } ) + if (it.bldgUnit.hasWaypoint) drawBldgUnitPolyline(it.bldgUnit) + bottomSheet .show(childFragmentManager, "BottomSheetAptUnitDetailsFragment") @@ -308,6 +351,31 @@ class EditAptUnitsMapFragment : Fragment(){ } + binding.saveWaypointButton.setOnClickListener { + val oldUnit = selectedBldgUnit!! + + val newUnit = BuildingUnit( + number = oldUnit.number, + floorNumber = oldUnit.floorNumber, + latitude = oldUnit.latitude, + longitude = oldUnit.longitude, + hasWaypoint = true, + waypointLatitude = pinDropMarker.position.latitude, + waypointLongitude = pinDropMarker.position.longitude + + ) + + selectedApt.value?.let { apt -> + apt.buildingUnits.remove(oldUnit) + apt.buildingUnits.add(newUnit) + + launchIO { + apartmentViewModel.updateApartment(apt) + selectedApt.postValue(apt) + } + } + } + binding.lifecycleOwner = this return binding.root @@ -486,6 +554,7 @@ class EditAptUnitsMapFragment : Fragment(){ } } this.hideAddUnitUI() + this.hideAddWaypointUI() } private fun refreshMapAtSpecificFloor(floor: String) { @@ -527,6 +596,7 @@ class EditAptUnitsMapFragment : Fragment(){ } this.hideAddUnitUI() + this.hideAddWaypointUI() } private fun hideAddUnitUI() { @@ -543,6 +613,7 @@ class EditAptUnitsMapFragment : Fragment(){ pinDropMarker.isVisible = false mainActivity.hideKeyBoard(binding.unitEditText) + binding.floorsSpinner.isEnabled = true } private fun showAddUnitUI() { @@ -561,6 +632,66 @@ class EditAptUnitsMapFragment : Fragment(){ binding.unitEditText.requestFocus() mainActivity.showKeyBoard(binding.unitEditText) binding.unitEditText.isEnabled = true + + hideAddWaypointUI() + binding.floorsSpinner.isEnabled = false + } + + private fun hideAddWaypointUI() { + val transition = Slide(Gravity.TOP) + transition.duration = 50 + transition.addTarget(binding.addWaypointInputView) + transition.addTarget(binding.saveWaypointButton) + transition.addTarget(binding.addWaypointTextView) + + TransitionManager.beginDelayedTransition(binding.editAptUnitsMapContainer, transition) + binding.addWaypointInputView.visibility = View.GONE + binding.saveWaypointButton.visibility = View.GONE + binding.addWaypointTextView.visibility = View.GONE + + pinDropMarker.isVisible = false + binding.floorsSpinner.isEnabled = true + clearPolylines() + + } + + private fun showAddWaypointUI() { + val transition = Slide(Gravity.TOP) + transition.duration = 50 + transition.addTarget(binding.addWaypointInputView) + transition.addTarget(binding.saveWaypointButton) + transition.addTarget(binding.addWaypointTextView) + + TransitionManager.beginDelayedTransition(binding.editAptUnitsMapContainer, transition) + binding.addWaypointInputView.visibility = View.VISIBLE + binding.saveWaypointButton.visibility = View.VISIBLE + binding.addWaypointTextView.visibility = View.VISIBLE + + hideAddUnitUI() + binding.floorsSpinner.isEnabled = false + } + + private fun drawBldgUnitPolyline(unit: BuildingUnit) { + val polyline = gMap.addPolyline( + PolylineOptions() + .clickable(false) + .add( + LatLng(unit.waypointLatitude, unit.waypointLongitude), + LatLng(unit.latitude, unit.longitude) + ) + ) + + val pair = Util.stylePolyline(gMap, polyline) + activePolylinePairList.add(pair) + } + + private fun clearPolylines() { + activePolylinePairList.forEach { pair -> + pair?.first?.remove() + pair?.second?.remove() + } + + activePolylinePairList.clear() } } diff --git a/app/src/main/java/name/lmj0011/courierlocker/fragments/bottomsheets/BottomSheetAptBuildingDetailsFragment.kt b/app/src/main/java/name/lmj0011/courierlocker/fragments/bottomsheets/BottomSheetAptBuildingDetailsFragment.kt index d6e4a75..0aaa363 100644 --- a/app/src/main/java/name/lmj0011/courierlocker/fragments/bottomsheets/BottomSheetAptBuildingDetailsFragment.kt +++ b/app/src/main/java/name/lmj0011/courierlocker/fragments/bottomsheets/BottomSheetAptBuildingDetailsFragment.kt @@ -1,27 +1,27 @@ package name.lmj0011.courierlocker.fragments.bottomsheets -import android.annotation.SuppressLint import android.app.Dialog +import android.content.DialogInterface import android.content.Intent import android.net.Uri import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.Toast -import androidx.recyclerview.widget.DividerItemDecoration -import androidx.recyclerview.widget.ItemTouchHelper import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.bottomsheet.BottomSheetDialogFragment import name.lmj0011.courierlocker.R -import name.lmj0011.courierlocker.adapters.BuildingListAdapter import name.lmj0011.courierlocker.database.Building import name.lmj0011.courierlocker.databinding.BottomsheetFragmentAptBuildingDetailsBinding -import name.lmj0011.courierlocker.helpers.SwipeHelper -import name.lmj0011.courierlocker.helpers.Util -class BottomSheetAptBuildingDetailsFragment(private val building: Building, private val removeBuildingCallback: () -> Unit): BottomSheetDialogFragment() { +class BottomSheetAptBuildingDetailsFragment( + private val building: Building, + private val addWaypointCallback: () -> Unit, + private val removeWaypointCallback: () -> Unit, + private val removeBuildingCallback: () -> Unit, + private val dismissCallback: () -> Unit +): BottomSheetDialogFragment() { private lateinit var binding: BottomsheetFragmentAptBuildingDetailsBinding private lateinit var bottomSheetDialog: BottomSheetDialog @@ -47,21 +47,49 @@ class BottomSheetAptBuildingDetailsFragment(private val building: Building, priv setupObservers() } + override fun onDismiss(dialog: DialogInterface) { + super.onDismiss(dialog) + dismissCallback() + } + private fun setupBinding(view: View) { binding = BottomsheetFragmentAptBuildingDetailsBinding.bind(view) binding.buildingName.text = "Building ${building.number}" binding.navigateButton.setOnClickListener { - val gmmIntentUri = Uri.parse("google.navigation:q=${building.latitude},${building.longitude}") + var gmmIntentUri = Uri.parse("https://www.google.com/maps/dir/?api=1&destination=${building.latitude},${building.longitude}&travelmode=driving") + + if(building.hasWaypoint) { + gmmIntentUri = Uri.parse("https://www.google.com/maps/dir/?api=1&destination=${building.latitude},${building.longitude}&waypoints=${building.waypointLatitude},${building.waypointLongitude}&travelmode=driving") + } + val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri) mapIntent.setPackage("com.google.android.apps.maps") startActivity(mapIntent) } + binding.addWaypointButton.setOnClickListener { + addWaypointCallback() + dismiss() + } + + binding.removeWaypointButton.setOnClickListener { + removeWaypointCallback() + dismiss() + } + binding.deleteButton.setOnClickListener { removeBuildingCallback() dismiss() } + + if(building.hasWaypoint) { + binding.addWaypointButton.visibility = View.GONE + binding.removeWaypointButton.visibility = View.VISIBLE + } else { + binding.addWaypointButton.visibility = View.VISIBLE + binding.removeWaypointButton.visibility = View.GONE + } } private fun setupRecyclerView() {} diff --git a/app/src/main/java/name/lmj0011/courierlocker/fragments/bottomsheets/BottomSheetAptUnitDetailsFragment.kt b/app/src/main/java/name/lmj0011/courierlocker/fragments/bottomsheets/BottomSheetAptUnitDetailsFragment.kt index ab90476..39e29f1 100644 --- a/app/src/main/java/name/lmj0011/courierlocker/fragments/bottomsheets/BottomSheetAptUnitDetailsFragment.kt +++ b/app/src/main/java/name/lmj0011/courierlocker/fragments/bottomsheets/BottomSheetAptUnitDetailsFragment.kt @@ -1,33 +1,28 @@ package name.lmj0011.courierlocker.fragments.bottomsheets -import android.annotation.SuppressLint import android.app.Dialog +import android.content.DialogInterface import android.content.Intent import android.net.Uri import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.Toast -import androidx.recyclerview.widget.DividerItemDecoration -import androidx.recyclerview.widget.ItemTouchHelper import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.bottomsheet.BottomSheetDialogFragment import name.lmj0011.courierlocker.R -import name.lmj0011.courierlocker.adapters.BuildingListAdapter -import name.lmj0011.courierlocker.database.Building import name.lmj0011.courierlocker.database.BuildingUnit -import name.lmj0011.courierlocker.databinding.BottomsheetFragmentAptBuildingDetailsBinding import name.lmj0011.courierlocker.databinding.BottomsheetFragmentAptUnitDetailsBinding -import name.lmj0011.courierlocker.helpers.SwipeHelper -import name.lmj0011.courierlocker.helpers.Util class BottomSheetAptUnitDetailsFragment( private val buildingUnit: BuildingUnit, private val editBuildingUnitCallback: () -> Unit, - private val removeBuildingUnitCallback: () -> Unit): BottomSheetDialogFragment() -{ + private val addWaypointCallback: () -> Unit, + private val removeWaypointCallback: () -> Unit, + private val removeBuildingUnitCallback: () -> Unit, + private val dismissCallback: () -> Unit +): BottomSheetDialogFragment() { private lateinit var binding: BottomsheetFragmentAptUnitDetailsBinding private lateinit var bottomSheetDialog: BottomSheetDialog @@ -53,12 +48,22 @@ class BottomSheetAptUnitDetailsFragment( setupObservers() } + override fun onDismiss(dialog: DialogInterface) { + super.onDismiss(dialog) + dismissCallback() + } + private fun setupBinding(view: View) { binding = BottomsheetFragmentAptUnitDetailsBinding.bind(view) binding.unitName.text = "Unit ${buildingUnit.number}" binding.navigateButton.setOnClickListener { - val gmmIntentUri = Uri.parse("google.navigation:q=${buildingUnit.latitude},${buildingUnit.longitude}") + var gmmIntentUri = Uri.parse("https://www.google.com/maps/dir/?api=1&destination=${buildingUnit.latitude},${buildingUnit.longitude}&travelmode=driving") + + if(buildingUnit.hasWaypoint) { + gmmIntentUri = Uri.parse("https://www.google.com/maps/dir/?api=1&destination=${buildingUnit.latitude},${buildingUnit.longitude}&waypoints=${buildingUnit.waypointLatitude},${buildingUnit.waypointLongitude}&travelmode=driving") + } + val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri) mapIntent.setPackage("com.google.android.apps.maps") startActivity(mapIntent) @@ -69,10 +74,28 @@ class BottomSheetAptUnitDetailsFragment( dismiss() } + binding.addWaypointButton.setOnClickListener { + addWaypointCallback() + dismiss() + } + + binding.removeWaypointButton.setOnClickListener { + removeWaypointCallback() + dismiss() + } + binding.deleteButton.setOnClickListener { removeBuildingUnitCallback() dismiss() } + + if(buildingUnit.hasWaypoint) { + binding.addWaypointButton.visibility = View.GONE + binding.removeWaypointButton.visibility = View.VISIBLE + } else { + binding.addWaypointButton.visibility = View.VISIBLE + binding.removeWaypointButton.visibility = View.GONE + } } private fun setupRecyclerView() {} diff --git a/app/src/main/java/name/lmj0011/courierlocker/helpers/AppDataImportExportHelper.kt b/app/src/main/java/name/lmj0011/courierlocker/helpers/AppDataImportExportHelper.kt index a5c6625..eb73394 100644 --- a/app/src/main/java/name/lmj0011/courierlocker/helpers/AppDataImportExportHelper.kt +++ b/app/src/main/java/name/lmj0011/courierlocker/helpers/AppDataImportExportHelper.kt @@ -62,7 +62,10 @@ object AppDataImportExportHelper { jsonObject( "number" to bldg.number, "latitude" to bldg.latitude, - "longitude" to bldg.longitude + "longitude" to bldg.longitude, + "hasWaypoint" to bldg.hasWaypoint, + "waypointLatitude" to bldg.waypointLatitude, + "waypointLongitude" to bldg.waypointLongitude ) } ), @@ -72,7 +75,10 @@ object AppDataImportExportHelper { "number" to bldgUnit.number, "floorNumber" to bldgUnit.floorNumber, "latitude" to bldgUnit.latitude, - "longitude" to bldgUnit.longitude + "longitude" to bldgUnit.longitude, + "hasWaypoint" to bldgUnit.hasWaypoint, + "waypointLatitude" to bldgUnit.waypointLatitude, + "waypointLongitude" to bldgUnit.waypointLongitude ) } ) diff --git a/app/src/main/java/name/lmj0011/courierlocker/helpers/Const.kt b/app/src/main/java/name/lmj0011/courierlocker/helpers/Const.kt index 143f930..ea06316 100644 --- a/app/src/main/java/name/lmj0011/courierlocker/helpers/Const.kt +++ b/app/src/main/java/name/lmj0011/courierlocker/helpers/Const.kt @@ -4,4 +4,7 @@ object Const { const val DEFAULT_PAGE_COUNT = 100 // amount to page from db when using androidx.paging const val DEFAULT_PREFETCH_DISTANCE = 25 const val DEFAULT_RECENT_TRIPS_LIMIT = 3 + const val BUILDING_SELECTION_MODE = 0 + const val BUILDING_UNIT_SELECTION_MODE = 0 + const val WAYPOINT_SELECTION_MODE = 1 } \ No newline at end of file diff --git a/app/src/main/java/name/lmj0011/courierlocker/helpers/Util.kt b/app/src/main/java/name/lmj0011/courierlocker/helpers/Util.kt index 3b55f96..24d148c 100644 --- a/app/src/main/java/name/lmj0011/courierlocker/helpers/Util.kt +++ b/app/src/main/java/name/lmj0011/courierlocker/helpers/Util.kt @@ -7,6 +7,8 @@ import android.text.Html import android.text.Spanned import android.view.View import androidx.paging.PagingConfig +import com.google.android.libraries.maps.GoogleMap +import com.google.android.libraries.maps.model.* import kotlinx.coroutines.delay import name.lmj0011.courierlocker.database.GateCode import name.lmj0011.courierlocker.database.Trip @@ -22,6 +24,42 @@ import java.text.NumberFormat object Util { val numberFormatInstance: NumberFormat = NumberFormat.getCurrencyInstance() + /** + * Styles the polyline, based on type. + * @param polyline The polyline object that needs styling. + */ + fun stylePolyline(gMap: GoogleMap, polyline: Polyline): Pair { + val dot: PatternItem = Dot() + val gap: PatternItem = Gap(20f) + val dash: PatternItem = Dash(20f) + val circleRadius = 0.9144 // 0.9144m == 6ft + val lightOrangeColor = -0x657db + val darkOrangeColor = -0xa80e9 + + // Create a stroke pattern of a dot followed by a gap, a dash, and another gap. + val polylinePattern = listOf(dot, gap, dash, gap) + + polyline.startCap = RoundCap() + polyline.endCap = RoundCap() + polyline.width = 8f + polyline.color = lightOrangeColor + polyline.pattern = polylinePattern + polyline.jointType = JointType.ROUND + + val circle = gMap.addCircle( + CircleOptions() + .center(LatLng(polyline.points.first().latitude, polyline.points.first().longitude)) + .radius(circleRadius) + .strokeWidth(10f) + .strokeColor(darkOrangeColor) + .fillColor(darkOrangeColor) + .clickable(false) + ) + + return Pair(polyline, circle) + } + + /** * Shortens a Postal Address to only the street name if possible * diff --git a/app/src/main/res/drawable/ic_baseline_add_location_alt_24.xml b/app/src/main/res/drawable/ic_baseline_add_location_alt_24.xml new file mode 100644 index 0000000..1845e7b --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_add_location_alt_24.xml @@ -0,0 +1,4 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_wrong_location_24.xml b/app/src/main/res/drawable/ic_baseline_wrong_location_24.xml new file mode 100644 index 0000000..707859a --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_wrong_location_24.xml @@ -0,0 +1,5 @@ + + + + diff --git a/app/src/main/res/layout/bottomsheet_fragment_apt_building_details.xml b/app/src/main/res/layout/bottomsheet_fragment_apt_building_details.xml index db19bb7..8dc0bad 100644 --- a/app/src/main/res/layout/bottomsheet_fragment_apt_building_details.xml +++ b/app/src/main/res/layout/bottomsheet_fragment_apt_building_details.xml @@ -35,6 +35,32 @@ app:iconPadding="10dp" android:text="Navigate" /> + + + + + + + + + - - + + + + + + + +