checkpoint

master
voussoir 2023-03-14 22:14:25 -07:00
parent b0edefcb4b
commit 0133524fa2
7 changed files with 226 additions and 45 deletions

View File

@ -30,8 +30,8 @@ import java.util.*
data class Track (
val database: Database,
val device_id: String,
val start_time: Date,
val stop_time: Date,
var start_time: Date,
var end_time: Date,
var name: String = "",
val trkpts: ArrayDeque<Trkpt> = ArrayDeque<Trkpt>(),
var view_latitude: Double = Keys.DEFAULT_LATITUDE,
@ -135,7 +135,6 @@ data class Track (
continue
}
stats.distance += previous.toLocation().distanceTo(trkpt.toLocation())
Log.i("VOUSSOIR", previous.toLocation().distanceTo(trkpt.toLocation()).toString())
val ascentdiff = trkpt.altitude - previous.altitude
if (ascentdiff > 0)
{
@ -169,8 +168,9 @@ data class Track (
{
val cursor: Cursor = database.connection.rawQuery(
"SELECT lat, lon, time, ele, accuracy, sat FROM trkpt WHERE device_id = ? AND time > ? AND time < ? ORDER BY time ASC",
arrayOf(device_id, start_time.time.toString(), stop_time.time.toString())
arrayOf(device_id, start_time.time.toString(), end_time.time.toString())
)
Log.i("VOUSSOIR", "Querying points between ${start_time} -- ${end_time}")
val COLUMN_LAT = cursor.getColumnIndex("lat")
val COLUMN_LON = cursor.getColumnIndex("lon")
val COLUMN_ELE = cursor.getColumnIndex("ele")

View File

@ -49,9 +49,8 @@ class TrackFragment : Fragment(), YesNoDialog.YesNoDialogListener
name=this.requireArguments().getString(Keys.ARG_TRACK_TITLE, ""),
device_id= this.requireArguments().getString(Keys.ARG_TRACK_DEVICE_ID, ""),
start_time= iso8601_format.parse(this.requireArguments().getString(Keys.ARG_TRACK_START_TIME)!!),
stop_time=iso8601_format.parse(this.requireArguments().getString(Keys.ARG_TRACK_STOP_TIME)!!),
end_time=iso8601_format.parse(this.requireArguments().getString(Keys.ARG_TRACK_STOP_TIME)!!),
)
track.load_trkpts()
layout = TrackFragmentLayoutHolder(activity as Context, inflater, container, track)
// set up share button

View File

@ -91,7 +91,7 @@ class TracklistFragment : Fragment(), TracklistAdapter.TracklistAdapterListener,
Keys.ARG_TRACK_TITLE to track.name,
Keys.ARG_TRACK_DEVICE_ID to track.device_id,
Keys.ARG_TRACK_START_TIME to iso8601_format.format(track.start_time),
Keys.ARG_TRACK_STOP_TIME to iso8601_format.format(track.stop_time),
Keys.ARG_TRACK_STOP_TIME to iso8601_format.format(track.end_time),
)
findNavController().navigate(R.id.fragment_track, bundle)
}

View File

@ -69,7 +69,7 @@ class TracklistAdapter(val fragment: Fragment, val database: Database) : Recycle
Log.i("VOUSSOIR", "TracklistAdapter prep track ${trackdate}")
if (start_time != null && stop_time != null)
{
val track = Track(database=database, device_id=device_id, start_time=start_time, stop_time=stop_time)
val track = Track(database=database, device_id=device_id, start_time=start_time, end_time=stop_time)
track.name = "$trackdate $device_id"
tracks.add(track)
}

View File

@ -18,10 +18,15 @@ package org.y20k.trackbook.ui
import android.app.Activity
import android.content.Context
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.DatePicker
import android.widget.ImageButton
import android.widget.TimePicker
import android.widget.Toast
import androidx.constraintlayout.widget.Group
import androidx.core.widget.NestedScrollView
@ -34,19 +39,17 @@ import org.osmdroid.events.ZoomEvent
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.OverlayItem
import org.osmdroid.views.overlay.TilesOverlay
import org.osmdroid.views.overlay.compass.CompassOverlay
import org.osmdroid.views.overlay.compass.InternalCompassOrientationProvider
import org.osmdroid.views.overlay.simplefastpoint.SimpleFastPointOverlay
import org.y20k.trackbook.Keys
import org.y20k.trackbook.R
import org.y20k.trackbook.Track
import org.y20k.trackbook.TrackStatistics
import org.y20k.trackbook.helpers.*
import java.util.*
/*
* TrackFragmentLayoutHolder class
*/
//data class TrackFragmentLayoutHolder(private var context: Context, private var markerListener: MapOverlayHelper.MarkerListener, private var inflater: LayoutInflater, private var statusBarHeight: Int, private var container: ViewGroup?, var track: Track): MapListener { TODO REMOVE
data class TrackFragmentLayoutHolder(
private var context: Context,
private var inflater: LayoutInflater,
@ -54,11 +57,16 @@ data class TrackFragmentLayoutHolder(
var track: Track
): MapListener
{
/* Main class variables */
val rootView: View
val save_track_button: ImageButton
val deleteButton: ImageButton
val trackNameView: MaterialTextView
val track_query_start_date: DatePicker
val track_query_start_time: TimePicker
val track_query_end_date: DatePicker
val track_query_end_time: TimePicker
var track_query_start_time_previous: Int
var track_query_end_time_previous: Int
private val mapView: MapView
private var controller: IMapController
private val statisticsSheetBehavior: BottomSheetBehavior<View>
@ -78,17 +86,93 @@ data class TrackFragmentLayoutHolder(
private val negativeElevationView: MaterialTextView
private val elevationDataViews: Group
private val useImperialUnits: Boolean
private val handler: Handler = Handler(Looper.getMainLooper())
private var special_points_overlay: ItemizedIconOverlay<OverlayItem>? = null
private var track_overlay: SimpleFastPointOverlay? = null
val RERENDER_DELAY: Long = 1000
init
{
// find views
rootView = inflater.inflate(R.layout.fragment_track, container, false)
mapView = rootView.findViewById(R.id.map)
save_track_button = rootView.findViewById(R.id.save_button)
deleteButton = rootView.findViewById(R.id.delete_button)
trackNameView = rootView.findViewById(R.id.statistics_track_name_headline)
// basic map setup
track.load_trkpts()
val actual_start_time: Date = if (track.trkpts.isEmpty()) track.start_time else Date(track.trkpts.first().time)
val actual_end_time: Date = if (track.trkpts.isEmpty()) track.end_time else Date(track.trkpts.last().time)
track_query_start_date = rootView.findViewById(R.id.track_query_start_date)
val start_cal = GregorianCalendar()
start_cal.time = actual_start_time
track_query_start_date.init(start_cal.get(Calendar.YEAR), start_cal.get(Calendar.MONTH), start_cal.get(Calendar.DAY_OF_MONTH), object: DatePicker.OnDateChangedListener {
override fun onDateChanged(p0: DatePicker?, p1: Int, p2: Int, p3: Int)
{
handler.removeCallbacks(requery_and_render)
handler.postDelayed(requery_and_render, RERENDER_DELAY)
}
})
track_query_start_time = rootView.findViewById(R.id.track_query_start_time)
track_query_start_time.setIs24HourView(true)
track_query_start_time.hour = actual_start_time.hours
track_query_start_time.minute = actual_start_time.minutes
track_query_start_time_previous = (actual_start_time.hours * 60) + actual_start_time.minutes
track_query_start_time.setOnTimeChangedListener(object : TimePicker.OnTimeChangedListener{
override fun onTimeChanged(p0: TimePicker?, p1: Int, p2: Int)
{
handler.removeCallbacks(requery_and_render)
val newminute = (p1 * 60) + p2
Log.i("VOUSSOIR", "End time changed $newminute")
if (newminute < track_query_start_time_previous && (track_query_start_time_previous - newminute > 60))
{
increment_datepicker(track_query_start_date)
}
else if (newminute > track_query_start_time_previous && (newminute - track_query_start_time_previous > 60))
{
decrement_datepicker(track_query_start_date)
}
track_query_start_time_previous = newminute
handler.postDelayed(requery_and_render, RERENDER_DELAY)
}
})
track_query_end_date = rootView.findViewById(R.id.track_query_end_date)
val end_cal = GregorianCalendar()
end_cal.time = actual_end_time
track_query_end_date.init(end_cal.get(Calendar.YEAR), end_cal.get(Calendar.MONTH), end_cal.get(Calendar.DAY_OF_MONTH), object: DatePicker.OnDateChangedListener {
override fun onDateChanged(p0: DatePicker?, p1: Int, p2: Int, p3: Int)
{
handler.removeCallbacks(requery_and_render)
handler.postDelayed(requery_and_render, RERENDER_DELAY)
}
})
track_query_end_time = rootView.findViewById(R.id.track_query_end_time)
track_query_end_time.setIs24HourView(true)
track_query_end_time.hour = actual_end_time.hours
track_query_end_time.minute = actual_end_time.minutes
track_query_end_time_previous = (actual_end_time.hours * 60) + actual_end_time.minutes
track_query_end_time.setOnTimeChangedListener(object : TimePicker.OnTimeChangedListener{
override fun onTimeChanged(p0: TimePicker?, p1: Int, p2: Int)
{
handler.removeCallbacks(requery_and_render)
val newminute = (p1 * 60) + p2
Log.i("VOUSSOIR", "End time changed $newminute")
if (newminute < track_query_end_time_previous && (track_query_end_time_previous - newminute > 60))
{
increment_datepicker(track_query_end_date)
}
else if (newminute > track_query_end_time_previous && (newminute - track_query_end_time_previous > 60))
{
decrement_datepicker(track_query_end_date)
}
track_query_end_time_previous = newminute
handler.postDelayed(requery_and_render, RERENDER_DELAY)
}
})
controller = mapView.controller
mapView.addMapListener(this)
mapView.isTilesScaledToDpi = true
@ -99,7 +183,6 @@ data class TrackFragmentLayoutHolder(
controller.setCenter(GeoPoint(track.view_latitude, track.view_longitude))
controller.setZoom(Keys.DEFAULT_ZOOM_LEVEL)
// get views for statistics sheet
statisticsSheet = rootView.findViewById(R.id.statistics_sheet)
statisticsView = rootView.findViewById(R.id.statistics_view)
distanceView = rootView.findViewById(R.id.statistics_data_distance)
@ -116,36 +199,59 @@ data class TrackFragmentLayoutHolder(
negativeElevationView = rootView.findViewById(R.id.statistics_data_negative_elevation)
elevationDataViews = rootView.findViewById(R.id.elevation_data)
// get measurement unit system
useImperialUnits = PreferencesHelper.loadUseImperialUnits()
// set dark map tiles, if necessary
if (AppThemeHelper.isDarkModeOn(context as Activity)) {
mapView.overlayManager.tilesOverlay.setColorFilter(TilesOverlay.INVERT_COLORS)
}
// add compass to map
val compassOverlay = CompassOverlay(context, InternalCompassOrientationProvider(context), mapView)
compassOverlay.enableCompass()
compassOverlay.setCompassCenter(36f, 36f)
// compassOverlay.setCompassCenter(36f, 36f + (statusBarHeight / UiHelper.getDensityScalingFactor(context))) TODO REMOVE
mapView.overlays.add(compassOverlay)
if (track.trkpts.isNotEmpty()) {
createSpecialMakersTrackOverlay(context, mapView, track.trkpts, Keys.STATE_TRACKING_STOPPED, displayStartEndMarker = true)
createTrackOverlay(context, mapView, track.trkpts, Keys.STATE_TRACKING_STOPPED)
}
// set up and show statistics sheet
statisticsSheetBehavior = BottomSheetBehavior.from<View>(statisticsSheet)
statisticsSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
render_track()
}
fun render_track()
{
if (special_points_overlay != null)
{
mapView.overlays.remove(special_points_overlay)
mapView.overlays.remove(track_overlay)
}
if (track.trkpts.isNotEmpty())
{
special_points_overlay = createSpecialMakersTrackOverlay(context, mapView, track.trkpts, Keys.STATE_TRACKING_STOPPED, displayStartEndMarker = true)
track_overlay = createTrackOverlay(context, mapView, track.trkpts, Keys.STATE_TRACKING_STOPPED)
}
setupStatisticsViews()
}
/* Sets up the statistics sheet */
fun get_datetime(datepicker: DatePicker, timepicker: TimePicker, seconds: Int): Date
{
val cal = GregorianCalendar.getInstance()
cal.set(datepicker.year, datepicker.month, datepicker.dayOfMonth, timepicker.hour, timepicker.minute, seconds)
Log.i("VOUSSOIR", cal.time.toString())
return cal.time
}
fun decrement_datepicker(picker: DatePicker)
{
val cal = GregorianCalendar.getInstance()
cal.set(picker.year, picker.month, picker.dayOfMonth)
cal.add(Calendar.DATE, -1)
picker.updateDate(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH))
}
fun increment_datepicker(picker: DatePicker)
{
val cal = GregorianCalendar.getInstance()
cal.set(picker.year, picker.month, picker.dayOfMonth)
cal.add(Calendar.DATE, 1)
picker.updateDate(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH))
}
private fun setupStatisticsViews()
{
// populate views
val stats: TrackStatistics = track.statistics()
trackNameView.text = track.name
distanceView.text = LengthUnitHelper.convertDistanceToString(stats.distance, useImperialUnits)
@ -153,7 +259,7 @@ data class TrackFragmentLayoutHolder(
durationView.text = DateTimeHelper.convertToReadableTime(context, stats.duration)
velocityView.text = LengthUnitHelper.convertToVelocityString(stats.velocity, useImperialUnits)
recordingStartView.text = DateTimeHelper.convertToReadableDateAndTime(track.start_time)
recordingStopView.text = DateTimeHelper.convertToReadableDateAndTime(track.stop_time)
recordingStopView.text = DateTimeHelper.convertToReadableDateAndTime(track.end_time)
maxAltitudeView.text = LengthUnitHelper.convertDistanceToString(stats.max_altitude, useImperialUnits)
minAltitudeView.text = LengthUnitHelper.convertDistanceToString(stats.min_altitude, useImperialUnits)
positiveElevationView.text = LengthUnitHelper.convertDistanceToString(stats.total_ascent, useImperialUnits)
@ -192,5 +298,17 @@ data class TrackFragmentLayoutHolder(
return (event != null)
}
private val requery_and_render: Runnable = object : Runnable {
override fun run()
{
Log.i("VOUSSOIR", "requery_and_render")
track.start_time = get_datetime(track_query_start_date, track_query_start_time, seconds=0)
track.end_time = get_datetime(track_query_end_date, track_query_end_time, seconds=59)
track.load_trkpts()
Log.i("VOUSSOIR", "Reloaded ${track.trkpts.size} trkpts.")
render_track()
mapView.invalidate()
}
}
}

View File

@ -7,18 +7,81 @@
android:layout_height="match_parent"
tools:context=".MainActivity">
<!-- OSM MAP -->
<org.osmdroid.views.MapView
android:id="@+id/map"
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:contentDescription="@string/descr_map_last_track"
app:layout_anchor="@+id/map"
app:layout_anchorGravity="center">
>
</org.osmdroid.views.MapView>
<DatePicker
android:id="@+id/track_query_start_date"
android:layout_width="wrap_content"
android:layout_height="130dp"
android:translationX="-45dp"
android:translationY="-30dp"
android:calendarViewShown="false"
android:datePickerMode="spinner"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:scaleX="0.5"
android:scaleY="0.5"
/>
<TimePicker
android:id="@+id/track_query_start_time"
android:layout_width="wrap_content"
android:layout_height="130dp"
android:translationX="-150dp"
android:translationY="-30dp"
android:timePickerMode="spinner"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="@+id/track_query_start_date"
android:scaleX="0.5"
android:scaleY="0.5"
/>
<DatePicker
android:id="@+id/track_query_end_date"
android:layout_width="wrap_content"
android:layout_height="130dp"
android:translationX="-45dp"
android:translationY="-100dp"
android:datePickerMode="spinner"
android:calendarViewShown="false"
app:layout_constraintTop_toBottomOf="@+id/track_query_start_date"
app:layout_constraintStart_toStartOf="parent"
android:scaleX="0.5"
android:scaleY="0.5"
/>
<TimePicker
android:id="@+id/track_query_end_time"
android:layout_width="wrap_content"
android:layout_height="130dp"
android:translationX="-150dp"
android:translationY="-100dp"
android:timePickerMode="spinner"
app:layout_constraintTop_toBottomOf="@+id/track_query_start_time"
app:layout_constraintStart_toEndOf="@+id/track_query_start_date"
android:scaleX="0.5"
android:scaleY="0.5"
/>
<org.osmdroid.views.MapView
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/track_query_end_time"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:contentDescription="@string/descr_map_last_track"
>
</org.osmdroid.views.MapView>
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- BOTTOM SHEET -->
<androidx.core.widget.NestedScrollView

View File

@ -22,6 +22,7 @@
app:layout_constraintVertical_bias="0" />
<!-- ONBOARDING -->
<include
layout="@layout/track_onboarding"
android:layout_width="0dp"