checkpoint
This commit is contained in:
		
							parent
							
								
									172ca703a9
								
							
						
					
					
						commit
						62675e1b97
					
				
					 7 changed files with 169 additions and 35 deletions
				
			
		|  | @ -47,6 +47,7 @@ class Database(trackbook: Trackbook) | |||
| 
 | ||||
|     fun insert_trkpt(device_id: String, trkpt: Trkpt) | ||||
|     { | ||||
|         Log.i("VOUSSOIR", "Database.insert_trkpt") | ||||
|         val values = ContentValues().apply { | ||||
|             put("device_id", device_id) | ||||
|             put("lat", trkpt.latitude) | ||||
|  | @ -63,6 +64,24 @@ class Database(trackbook: Trackbook) | |||
|         connection.insert("trkpt", null, values) | ||||
|     } | ||||
| 
 | ||||
|     fun insert_homepoint(name: String, latitude: Double, longitude: Double, radius: Double) | ||||
|     { | ||||
|         Log.i("VOUSSOIR", "Database.insert_homepoint") | ||||
|         val values = ContentValues().apply { | ||||
|             put("lat", latitude) | ||||
|             put("lon", longitude) | ||||
|             put("radius", radius) | ||||
|             put("name", name) | ||||
|         } | ||||
|         if (! connection.inTransaction()) | ||||
|         { | ||||
|             connection.beginTransaction() | ||||
|         } | ||||
|         connection.insert("homepoints", null, values) | ||||
|         commit() | ||||
|         trackbook.load_homepoints() | ||||
|     } | ||||
| 
 | ||||
|     private fun initialize_tables() | ||||
|     { | ||||
|         this.connection.beginTransaction() | ||||
|  |  | |||
|  | @ -17,6 +17,7 @@ | |||
| package org.y20k.trackbook | ||||
| 
 | ||||
| import android.Manifest | ||||
| import android.app.Dialog | ||||
| import android.content.* | ||||
| import android.content.pm.PackageManager | ||||
| import android.content.res.Resources | ||||
|  | @ -29,6 +30,9 @@ import android.view.LayoutInflater | |||
| import android.view.View | ||||
| import android.view.ViewGroup | ||||
| import android.view.WindowManager | ||||
| import android.widget.Button | ||||
| import android.widget.EditText | ||||
| import android.widget.TextView | ||||
| import androidx.activity.result.contract.ActivityResultContracts.RequestPermission | ||||
| import androidx.core.content.ContextCompat | ||||
| import androidx.core.view.isVisible | ||||
|  | @ -37,10 +41,12 @@ import com.google.android.material.floatingactionbutton.ExtendedFloatingActionBu | |||
| import com.google.android.material.floatingactionbutton.FloatingActionButton | ||||
| import com.google.android.material.snackbar.Snackbar | ||||
| import org.osmdroid.api.IMapController | ||||
| import org.osmdroid.events.MapEventsReceiver | ||||
| import org.osmdroid.tileprovider.tilesource.TileSourceFactory | ||||
| import org.osmdroid.util.GeoPoint | ||||
| import org.osmdroid.views.MapView | ||||
| import org.osmdroid.views.overlay.ItemizedIconOverlay | ||||
| import org.osmdroid.views.overlay.MapEventsOverlay | ||||
| import org.osmdroid.views.overlay.Overlay | ||||
| import org.osmdroid.views.overlay.OverlayItem | ||||
| import org.osmdroid.views.overlay.Polygon | ||||
|  | @ -70,7 +76,7 @@ class MapFragment : Fragment() | |||
| 
 | ||||
|     private lateinit var trackbook: Trackbook | ||||
|     lateinit var rootView: View | ||||
|     var userInteraction: Boolean = false | ||||
|     var continuous_auto_center: Boolean = true | ||||
|     lateinit var currentLocationButton: FloatingActionButton | ||||
|     lateinit var zoom_in_button: FloatingActionButton | ||||
|     lateinit var zoom_out_button: FloatingActionButton | ||||
|  | @ -124,6 +130,12 @@ class MapFragment : Fragment() | |||
|         mainButton = rootView.findViewById(R.id.main_button) | ||||
|         locationErrorBar = Snackbar.make(mapView, String(), Snackbar.LENGTH_INDEFINITE) | ||||
| 
 | ||||
|         mapView.setOnLongClickListener{ | ||||
|             Log.i("VOUSSOIR", "mapview longpress") | ||||
|             true | ||||
|         } | ||||
|         mapView.isLongClickable = true | ||||
| 
 | ||||
|         // basic map setup | ||||
|         controller = mapView.controller | ||||
|         mapView.isTilesScaledToDpi = true | ||||
|  | @ -133,16 +145,13 @@ class MapFragment : Fragment() | |||
|         zoomLevel = PreferencesHelper.loadZoomLevel() | ||||
|         controller.setZoom(zoomLevel) | ||||
| 
 | ||||
|         // set dark map tiles, if necessary | ||||
|         if (AppThemeHelper.isDarkModeOn(requireActivity())) | ||||
|         { | ||||
|             mapView.overlayManager.tilesOverlay.setColorFilter(TilesOverlay.INVERT_COLORS) | ||||
|         } | ||||
| 
 | ||||
|         // store Density Scaling Factor | ||||
|         val densityScalingFactor: Float = UiHelper.getDensityScalingFactor(requireContext()) | ||||
| 
 | ||||
|         // add compass to map | ||||
|         val compassOverlay = CompassOverlay(requireContext(), InternalCompassOrientationProvider(requireContext()), mapView) | ||||
|         compassOverlay.enableCompass() | ||||
|         // compassOverlay.setCompassCenter(36f, 36f + (statusBarHeight / densityScalingFactor)) // TODO uncomment when transparent status bar is re-implemented | ||||
|  | @ -167,8 +176,47 @@ class MapFragment : Fragment() | |||
|         // initialize main button state | ||||
|         update_main_button() | ||||
| 
 | ||||
|         // listen for user interaction | ||||
|         addInteractionListener() | ||||
|         mapView.setOnTouchListener { v, event -> | ||||
|             continuous_auto_center = false | ||||
|             false | ||||
|         } | ||||
| 
 | ||||
|         val receiver: MapEventsReceiver = object: MapEventsReceiver | ||||
|         { | ||||
|             override fun singleTapConfirmedHelper(p: GeoPoint?): Boolean | ||||
|             { | ||||
|                 return true | ||||
|             } | ||||
| 
 | ||||
|             override fun longPressHelper(point: GeoPoint): Boolean | ||||
|             { | ||||
|                 Log.i("VOUSSOIR", "MapFragment MapEventsReceiver.longPressHelper") | ||||
|                 val dialog = Dialog(activity as Context) | ||||
|                 dialog.setContentView(R.layout.dialog_homepoint) | ||||
|                 dialog.setTitle("Homepoint") | ||||
| 
 | ||||
|                 (dialog.findViewById(R.id.homepoint_dialog_title) as TextView).text = "Add a homepoint" | ||||
| 
 | ||||
|                 val name_input: EditText = dialog.findViewById(R.id.homepoint_name_input) | ||||
|                 val radius_input: EditText = dialog.findViewById(R.id.homepoint_radius_input) | ||||
|                 val cancel_button: Button = dialog.findViewById(R.id.homepoint_delete_cancel_button) | ||||
|                 val save_button: Button = dialog.findViewById(R.id.homepoint_save_button) | ||||
|                 cancel_button.text = "Cancel" | ||||
|                 cancel_button.setOnClickListener { | ||||
|                     dialog.cancel() | ||||
|                 } | ||||
|                 save_button.setOnClickListener { | ||||
|                     app.database.insert_homepoint(name=name_input.text.toString(), latitude=point.latitude, longitude=point.longitude, radius=radius_input.text.toString().toDouble()) | ||||
|                     app.load_homepoints() | ||||
|                     create_homepoint_overlays(requireContext(), mapView, app.homepoints) | ||||
|                     dialog.dismiss() | ||||
|                 } | ||||
| 
 | ||||
|                 dialog.show() | ||||
|                 return true | ||||
|             } | ||||
|         } | ||||
|         mapView.overlays.add(MapEventsOverlay(receiver)) | ||||
| 
 | ||||
|         // set up buttons | ||||
|         mainButton.setOnClickListener { | ||||
|  | @ -338,28 +386,19 @@ class MapFragment : Fragment() | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private fun addInteractionListener() | ||||
|     { | ||||
|         mapView.setOnTouchListener { v, event -> | ||||
|             userInteraction = true | ||||
|             false | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fun centerMap(location: Location, animated: Boolean = false) { | ||||
|         val position = GeoPoint(location.latitude, location.longitude) | ||||
|         when (animated) { | ||||
|             true -> controller.animateTo(position) | ||||
|             false -> controller.setCenter(position) | ||||
|         } | ||||
|         userInteraction = false | ||||
|         continuous_auto_center = true | ||||
|     } | ||||
| 
 | ||||
|     fun saveBestLocationState(currentBestLocation: Location) { | ||||
|         PreferencesHelper.saveCurrentBestLocation(currentBestLocation) | ||||
|         PreferencesHelper.saveZoomLevel(mapView.zoomLevelDouble) | ||||
|         // reset user interaction state | ||||
|         userInteraction = false | ||||
|         continuous_auto_center = true | ||||
|     } | ||||
| 
 | ||||
|     fun clear_current_position_overlays() | ||||
|  | @ -377,7 +416,7 @@ class MapFragment : Fragment() | |||
|     /* Mark current position on map */ | ||||
|     fun create_current_position_overlays(location: Location, trackingState: Int = Keys.STATE_TRACKING_STOPPED) | ||||
|     { | ||||
|         Log.i("VOUSSOIR", "MapFragmentLayoutHolder.markCurrentPosition") | ||||
|         // Log.i("VOUSSOIR", "MapFragmentLayoutHolder.markCurrentPosition") | ||||
| 
 | ||||
|         clear_current_position_overlays() | ||||
| 
 | ||||
|  | @ -555,7 +594,7 @@ class MapFragment : Fragment() | |||
|             create_current_position_overlays(currentBestLocation, trackingState) | ||||
|             create_current_track_overlay(track, trackingState) | ||||
|             // center map, if it had not been dragged/zoomed before | ||||
|             if (!userInteraction) | ||||
|             if (continuous_auto_center) | ||||
|             { | ||||
|                 centerMap(currentBestLocation, true) | ||||
|             } | ||||
|  |  | |||
|  | @ -161,7 +161,7 @@ class SettingsFragment : PreferenceFragmentCompat(), YesNoDialog.YesNoDialogList | |||
|             PreferencesHelper.save_database_folder(path) | ||||
|             preferenceDatabaseFolder.summary = (getString(R.string.pref_database_folder_summary) + "\n" + path).trim() | ||||
|         } | ||||
|         preferenceDatabaseFolder.title = "Database Directory" | ||||
|         preferenceDatabaseFolder.title = getString(R.string.pref_database_folder) | ||||
|         preferenceDatabaseFolder.setIcon(R.drawable.ic_save_to_storage_24dp) | ||||
|         preferenceDatabaseFolder.key = Keys.PREF_DATABASE_DIRECTORY | ||||
|         preferenceDatabaseFolder.summary = (getString(R.string.pref_database_folder_summary) + "\n" + PreferencesHelper.load_database_folder()).trim() | ||||
|  | @ -175,7 +175,7 @@ class SettingsFragment : PreferenceFragmentCompat(), YesNoDialog.YesNoDialogList | |||
|             return@setOnPreferenceClickListener true | ||||
|         } | ||||
|         preferenceDatabaseFolder.setOnPreferenceChangeListener { preference, newValue -> | ||||
|             preferenceDatabaseFolder.summary = "Directory to contain your database file." + "\n" + newValue | ||||
|             preferenceDatabaseFolder.summary = getString(R.string.pref_database_folder_summary) + "\n" + newValue | ||||
|             return@setOnPreferenceChangeListener true | ||||
|         } | ||||
| 
 | ||||
|  |  | |||
|  | @ -29,6 +29,7 @@ import org.osmdroid.api.IGeoPoint | |||
| import org.osmdroid.util.GeoPoint | ||||
| import org.osmdroid.views.MapView | ||||
| import org.osmdroid.views.overlay.ItemizedIconOverlay | ||||
| import org.osmdroid.views.overlay.MapEventsOverlay | ||||
| import org.osmdroid.views.overlay.OverlayItem | ||||
| import org.osmdroid.views.overlay.simplefastpoint.LabelledGeoPoint | ||||
| import org.osmdroid.views.overlay.simplefastpoint.SimpleFastPointOverlay | ||||
|  | @ -125,11 +126,10 @@ fun createSpecialMakersTrackOverlay(context: Context, map_view: MapView, track: | |||
| 
 | ||||
| fun createOverlayItem(context: Context, latitude: Double, longitude: Double, accuracy: Float, provider: String, time: Long): OverlayItem | ||||
| { | ||||
|     val title: String = "${context.getString(R.string.marker_description_time)}: ${SimpleDateFormat.getTimeInstance(SimpleDateFormat.MEDIUM, Locale.getDefault()).format(time)}" | ||||
|     //val description: String = "${context.getString(R.string.marker_description_accuracy)}: ${DecimalFormat("#0.00").format(accuracy)} (${provider})" | ||||
|     val description: String = "${context.getString(R.string.marker_description_time)}: ${SimpleDateFormat.getTimeInstance(SimpleDateFormat.MEDIUM, Locale.getDefault()).format(time)} | ${context.getString(R.string.marker_description_accuracy)}: ${DecimalFormat("#0.00").format(accuracy)} (${provider})" | ||||
|     val position: GeoPoint = GeoPoint(latitude, longitude) | ||||
|     val item: OverlayItem = OverlayItem(title, description, position) | ||||
|     val title = "${context.getString(R.string.marker_description_time)}: ${SimpleDateFormat.getTimeInstance(SimpleDateFormat.MEDIUM, Locale.getDefault()).format(time)}" | ||||
|     val description = "${context.getString(R.string.marker_description_time)}: ${SimpleDateFormat.getTimeInstance(SimpleDateFormat.MEDIUM, Locale.getDefault()).format(time)} | ${context.getString(R.string.marker_description_accuracy)}: ${DecimalFormat("#0.00").format(accuracy)} (${provider})" | ||||
|     val position = GeoPoint(latitude, longitude) | ||||
|     val item = OverlayItem(title, description, position) | ||||
|     item.markerHotspot = OverlayItem.HotspotPlace.CENTER | ||||
|     return item | ||||
| } | ||||
|  |  | |||
							
								
								
									
										76
									
								
								app/src/main/res/layout/dialog_homepoint.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								app/src/main/res/layout/dialog_homepoint.xml
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,76 @@ | |||
| <?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="wrap_content" | ||||
|     android:layout_margin="16dp"> | ||||
| 
 | ||||
|     <TextView | ||||
|         android:id="@+id/homepoint_dialog_title" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:text="Homepoint" | ||||
|         app:layout_constraintStart_toStartOf="parent" | ||||
|         app:layout_constraintTop_toTopOf="parent" /> | ||||
| 
 | ||||
|     <TextView | ||||
|         android:id="@+id/homepoint_name_label" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_marginTop="16dp" | ||||
|         android:text="Name" | ||||
|         app:layout_constraintStart_toStartOf="parent" | ||||
|         app:layout_constraintTop_toBottomOf="@+id/homepoint_dialog_title" /> | ||||
| 
 | ||||
|     <EditText | ||||
|         android:id="@+id/homepoint_name_input" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:ems="10" | ||||
|         android:inputType="textPersonName" | ||||
|         android:minHeight="48dp" | ||||
|         android:text="" | ||||
|         app:layout_constraintStart_toStartOf="@+id/homepoint_name_label" | ||||
|         app:layout_constraintTop_toBottomOf="@+id/homepoint_name_label" /> | ||||
| 
 | ||||
|     <TextView | ||||
|         android:id="@+id/homepoint_radius_label" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_marginTop="16dp" | ||||
|         android:text="Radius" | ||||
|         app:layout_constraintStart_toStartOf="@+id/homepoint_name_input" | ||||
|         app:layout_constraintTop_toBottomOf="@+id/homepoint_name_input" /> | ||||
| 
 | ||||
|     <EditText | ||||
|         android:id="@+id/homepoint_radius_input" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:ems="10" | ||||
|         android:inputType="number" | ||||
|         android:minHeight="48dp" | ||||
|         app:layout_constraintStart_toStartOf="@+id/homepoint_radius_label" | ||||
|         app:layout_constraintTop_toBottomOf="@+id/homepoint_radius_label" /> | ||||
| 
 | ||||
|     <Button | ||||
|         android:id="@+id/homepoint_save_button" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_marginTop="16dp" | ||||
|         android:text="Save" | ||||
|         app:cornerRadius="8dp" | ||||
|         app:layout_constraintEnd_toEndOf="parent" | ||||
|         app:layout_constraintTop_toBottomOf="@+id/homepoint_radius_input" /> | ||||
| 
 | ||||
|     <Button | ||||
|         android:id="@+id/homepoint_delete_cancel_button" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_marginTop="16dp" | ||||
|         android:text="Delete" | ||||
|         app:cornerRadius="8dp" | ||||
|         app:layout_constraintStart_toStartOf="parent" | ||||
|         app:layout_constraintTop_toBottomOf="@+id/homepoint_radius_input" /> | ||||
| 
 | ||||
| </androidx.constraintlayout.widget.ConstraintLayout> | ||||
|  | @ -7,20 +7,19 @@ | |||
|     android:layout_height="match_parent" | ||||
|     tools:context=".MapFragment"> | ||||
| 
 | ||||
|     <!-- MAP --> | ||||
|     <org.osmdroid.views.MapView | ||||
|         android:id="@+id/map" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="match_parent" | ||||
|         android:contentDescription="@string/descr_map_current_track" | ||||
|         android:visibility="visible" /> | ||||
| 
 | ||||
|     <androidx.constraintlayout.widget.ConstraintLayout | ||||
|         android:id="@+id/container" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="match_parent" | ||||
|         app:layout_dodgeInsetEdges="bottom"> | ||||
| 
 | ||||
|         <org.osmdroid.views.MapView | ||||
|             android:id="@+id/map" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="match_parent" | ||||
|             android:contentDescription="@string/descr_map_current_track" | ||||
|             android:visibility="visible" /> | ||||
| 
 | ||||
|         <!-- BUTTON SAVE --> | ||||
| 
 | ||||
|         <!-- BUTTON CLEAR --> | ||||
|  |  | |||
|  | @ -86,9 +86,10 @@ | |||
|     <string name="pref_altitude_smoothing_value_title" translatable="false">Altitude Smoothing</string> | ||||
|     <string name="pref_auto_export_interval_summary">Automatically export GPX file after this many hours.</string> | ||||
|     <string name="pref_device_id_summary">A unique ID to distinguish tracks recorded across multiple devices:</string> | ||||
|     <string name="pref_database_folder_summary">Directory to contain your database file:</string> | ||||
|     <string name="pref_database_folder_summary">Directory to contain your database file. You could use Syncthing to sync with your PC!</string> | ||||
|     <string name="pref_auto_export_interval_title">Auto Export Interval</string> | ||||
|     <string name="pref_device_id">Device ID</string> | ||||
|     <string name="pref_database_folder">Database directory</string> | ||||
|     <string name="pref_advanced_title">Advanced</string> | ||||
|     <string name="pref_delete_non_starred_summary">Delete all recordings in \"Tracks\" that are not starred.</string> | ||||
|     <string name="pref_delete_non_starred_title">Delete Non-Starred Recordings</string> | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue