checkpoint

master
voussoir 2023-03-12 17:49:03 -07:00
parent 2c33cc88f7
commit 8cbfa729f0
9 changed files with 57 additions and 205 deletions

View File

@ -33,7 +33,6 @@ import android.view.WindowManager
import android.widget.Button import android.widget.Button
import android.widget.EditText import android.widget.EditText
import android.widget.TextView import android.widget.TextView
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts.RequestPermission import androidx.activity.result.contract.ActivityResultContracts.RequestPermission
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.isVisible import androidx.core.view.isVisible
@ -71,7 +70,6 @@ class MapFragment : Fragment()
private var trackingState: Int = Keys.STATE_TRACKING_STOPPED private var trackingState: Int = Keys.STATE_TRACKING_STOPPED
private var gpsProviderActive: Boolean = false private var gpsProviderActive: Boolean = false
private var networkProviderActive: Boolean = false private var networkProviderActive: Boolean = false
private lateinit var track: Track
private lateinit var currentBestLocation: Location private lateinit var currentBestLocation: Location
private lateinit var trackerService: TrackerService private lateinit var trackerService: TrackerService
@ -185,12 +183,13 @@ class MapFragment : Fragment()
dialog.cancel() dialog.cancel()
} }
save_button.setOnClickListener { save_button.setOnClickListener {
val radius = radius_input.text.toString().toDoubleOrNull() ?: 25.0
trackbook.database.insert_homepoint( trackbook.database.insert_homepoint(
id=random_long(), id=random_long(),
name=name_input.text.toString(), name=name_input.text.toString(),
latitude=point.latitude, latitude=point.latitude,
longitude=point.longitude, longitude=point.longitude,
radius=radius_input.text.toString().toDouble(), radius=radius,
) )
trackbook.load_homepoints() trackbook.load_homepoints()
create_homepoint_overlays(requireContext(), mapView, trackbook.homepoints) create_homepoint_overlays(requireContext(), mapView, trackbook.homepoints)
@ -221,6 +220,7 @@ class MapFragment : Fragment()
mapView.setOnTouchListener { v, event -> mapView.setOnTouchListener { v, event ->
continuous_auto_center = false continuous_auto_center = false
zoomLevel = mapView.zoomLevelDouble
false false
} }
@ -232,10 +232,12 @@ class MapFragment : Fragment()
centerMap(currentBestLocation, animated=true) centerMap(currentBestLocation, animated=true)
} }
zoom_in_button.setOnClickListener { zoom_in_button.setOnClickListener {
controller.zoomTo(mapView.zoomLevelDouble + 0.5, 250) zoomLevel += 0.5
controller.zoomTo(mapView.zoomLevelDouble + 0.5, 0)
} }
zoom_out_button.setOnClickListener { zoom_out_button.setOnClickListener {
controller.zoomTo(mapView.zoomLevelDouble - 0.5, 250) zoomLevel -= 0.5
controller.zoomTo(mapView.zoomLevelDouble - 0.5, 0)
} }
requireActivity().window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) requireActivity().window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
@ -247,7 +249,8 @@ class MapFragment : Fragment()
{ {
super.onStart() super.onStart()
// request location permission if denied // request location permission if denied
if (ContextCompat.checkSelfPermission(activity as Context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_DENIED) { if (ContextCompat.checkSelfPermission(activity as Context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_DENIED)
{
requestLocationPermissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION) requestLocationPermissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION)
} }
// bind to TrackerService // bind to TrackerService
@ -556,7 +559,7 @@ class MapFragment : Fragment()
} }
/* Overlay current track on map */ /* Overlay current track on map */
fun create_current_track_overlay(track: Track, trackingState: Int) fun create_current_track_overlay(trkpts: Collection<Trkpt>, trackingState: Int)
{ {
if (currentTrackOverlay != null) { if (currentTrackOverlay != null) {
mapView.overlays.remove(currentTrackOverlay) mapView.overlays.remove(currentTrackOverlay)
@ -564,9 +567,9 @@ class MapFragment : Fragment()
if (currentTrackSpecialMarkerOverlay != null) { if (currentTrackSpecialMarkerOverlay != null) {
mapView.overlays.remove(currentTrackSpecialMarkerOverlay) mapView.overlays.remove(currentTrackSpecialMarkerOverlay)
} }
if (track.trkpts.isNotEmpty()) { if (trkpts.isNotEmpty()) {
createTrackOverlay(requireContext(), mapView, track, trackingState) createTrackOverlay(requireContext(), mapView, trkpts, trackingState)
createSpecialMakersTrackOverlay(requireContext(), mapView, track, trackingState) createSpecialMakersTrackOverlay(requireContext(), mapView, trkpts, trackingState)
} }
} }
@ -608,7 +611,8 @@ class MapFragment : Fragment()
} }
private val connection = object : ServiceConnection { private val connection = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) { override fun onServiceConnected(className: ComponentName, service: IBinder)
{
bound = true bound = true
// get reference to tracker service // get reference to tracker service
val binder = service as TrackerService.LocalBinder val binder = service as TrackerService.LocalBinder
@ -622,7 +626,8 @@ class MapFragment : Fragment()
handler.removeCallbacks(periodicLocationRequestRunnable) handler.removeCallbacks(periodicLocationRequestRunnable)
handler.postDelayed(periodicLocationRequestRunnable, 0) handler.postDelayed(periodicLocationRequestRunnable, 0)
} }
override fun onServiceDisconnected(arg0: ComponentName) { override fun onServiceDisconnected(arg0: ComponentName)
{
// service has crashed, or was killed by the system // service has crashed, or was killed by the system
handleServiceUnbind() handleServiceUnbind()
} }
@ -632,17 +637,16 @@ class MapFragment : Fragment()
override fun run() override fun run()
{ {
currentBestLocation = trackerService.currentBestLocation currentBestLocation = trackerService.currentBestLocation
track = trackerService.track
gpsProviderActive = trackerService.gpsProviderActive gpsProviderActive = trackerService.gpsProviderActive
networkProviderActive = trackerService.networkProviderActive networkProviderActive = trackerService.networkProviderActive
trackingState = trackerService.trackingState trackingState = trackerService.trackingState
// update location and track // update location and track
create_current_position_overlays(currentBestLocation, trackingState) create_current_position_overlays(currentBestLocation, trackingState)
create_current_track_overlay(track, trackingState) create_current_track_overlay(trackerService.recent_trkpts, trackingState)
// center map, if it had not been dragged/zoomed before // center map, if it had not been dragged/zoomed before
if (continuous_auto_center) if (continuous_auto_center)
{ {
centerMap(currentBestLocation, true) centerMap(currentBestLocation, animated=false)
} }
handler.postDelayed(this, Keys.REQUEST_CURRENT_LOCATION_INTERVAL) handler.postDelayed(this, Keys.REQUEST_CURRENT_LOCATION_INTERVAL)
} }

View File

@ -26,8 +26,6 @@ import android.widget.Toast
import org.y20k.trackbook.helpers.iso8601_format import org.y20k.trackbook.helpers.iso8601_format
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
data class Track ( data class Track (
val database: Database, val database: Database,

View File

@ -29,14 +29,13 @@ import android.widget.Toast
import androidx.activity.result.ActivityResult import androidx.activity.result.ActivityResult
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import org.y20k.trackbook.dialogs.RenameTrackDialog
import org.y20k.trackbook.helpers.LogHelper import org.y20k.trackbook.helpers.LogHelper
import org.y20k.trackbook.helpers.iso8601_format import org.y20k.trackbook.helpers.iso8601_format
import org.y20k.trackbook.ui.TrackFragmentLayoutHolder import org.y20k.trackbook.ui.TrackFragmentLayoutHolder
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
class TrackFragment : Fragment(), RenameTrackDialog.RenameTrackListener, YesNoDialog.YesNoDialogListener class TrackFragment : Fragment(), YesNoDialog.YesNoDialogListener
{ {
/* Define log tag */ /* Define log tag */
private val TAG: String = LogHelper.makeLogTag(TrackFragment::class.java) private val TAG: String = LogHelper.makeLogTag(TrackFragment::class.java)
@ -59,12 +58,12 @@ class TrackFragment : Fragment(), RenameTrackDialog.RenameTrackListener, YesNoDi
layout = TrackFragmentLayoutHolder(activity as Context, inflater, container, track) layout = TrackFragmentLayoutHolder(activity as Context, inflater, container, track)
// set up share button // set up share button
layout.shareButton.setOnClickListener { layout.save_track_button.setOnClickListener {
openSaveGpxDialog() openSaveGpxDialog()
} }
// set up delete button // set up delete button
layout.deleteButton.setOnClickListener { layout.deleteButton.setOnClickListener {
val dialogMessage = "${getString(R.string.dialog_yes_no_message_delete_recording)}\n\n- ${layout.trackNameView.text}" val dialogMessage = "${getString(R.string.dialog_yes_no_message_delete_recording)}\n\n${layout.trackNameView.text}"
YesNoDialog(this@TrackFragment as YesNoDialog.YesNoDialogListener).show( YesNoDialog(this@TrackFragment as YesNoDialog.YesNoDialogListener).show(
context = activity as Context, context = activity as Context,
type = Keys.DIALOG_DELETE_TRACK, type = Keys.DIALOG_DELETE_TRACK,
@ -72,10 +71,6 @@ class TrackFragment : Fragment(), RenameTrackDialog.RenameTrackListener, YesNoDi
yesButton = R.string.dialog_yes_no_positive_button_delete_recording yesButton = R.string.dialog_yes_no_positive_button_delete_recording
) )
} }
// set up rename button
layout.editButton.setOnClickListener {
RenameTrackDialog(this as RenameTrackDialog.RenameTrackListener).show(activity as Context, layout.trackNameView.text.toString())
}
return layout.rootView return layout.rootView
} }
@ -135,7 +130,6 @@ class TrackFragment : Fragment(), RenameTrackDialog.RenameTrackListener, YesNoDi
/* Opens up a file picker to select the save location */ /* Opens up a file picker to select the save location */
private fun openSaveGpxDialog() private fun openSaveGpxDialog()
{ {
val context = this.activity as Context
val export_name: String = SimpleDateFormat("yyyy-MM-dd", Locale.US).format(layout.track.start_time) + " " + layout.track.device_id + Keys.GPX_FILE_EXTENSION val export_name: String = SimpleDateFormat("yyyy-MM-dd", Locale.US).format(layout.track.start_time) + " " + layout.track.device_id + Keys.GPX_FILE_EXTENSION
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply { val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE) addCategory(Intent.CATEGORY_OPENABLE)

View File

@ -31,7 +31,6 @@ import android.location.Location
import android.location.LocationListener import android.location.LocationListener
import android.location.LocationManager import android.location.LocationManager
import android.Manifest import android.Manifest
import android.content.ContentValues
import android.os.* import android.os.*
import android.util.Log import android.util.Log
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
@ -60,8 +59,9 @@ class TrackerService: Service(), SensorEventListener
var currentBestLocation: Location = getDefaultLocation() var currentBestLocation: Location = getDefaultLocation()
var lastCommit: Date = Keys.DEFAULT_DATE var lastCommit: Date = Keys.DEFAULT_DATE
var location_min_time_ms: Long = 0 var location_min_time_ms: Long = 0
private val RECENT_TRKPT_COUNT = 7200
var stepCountOffset: Float = 0f var stepCountOffset: Float = 0f
lateinit var track: Track lateinit var recent_trkpts: Deque<Trkpt>
var gpsLocationListenerRegistered: Boolean = false var gpsLocationListenerRegistered: Boolean = false
var networkLocationListenerRegistered: Boolean = false var networkLocationListenerRegistered: Boolean = false
var bound: Boolean = false var bound: Boolean = false
@ -170,10 +170,6 @@ class TrackerService: Service(), SensorEventListener
LocationManager.NETWORK_PROVIDER -> networkProviderActive = isNetworkEnabled(locationManager) LocationManager.NETWORK_PROVIDER -> networkProviderActive = isNetworkEnabled(locationManager)
} }
} }
override fun onStatusChanged(p0: String?, p1: Int, p2: Bundle?)
{
// deprecated method
}
} }
} }
@ -211,9 +207,9 @@ class TrackerService: Service(), SensorEventListener
super.onCreate() super.onCreate()
trackbook = (applicationContext as Trackbook) trackbook = (applicationContext as Trackbook)
trackbook.load_homepoints() trackbook.load_homepoints()
recent_trkpts = ArrayDeque<Trkpt>(RECENT_TRKPT_COUNT)
gpsOnly = PreferencesHelper.loadGpsOnly() gpsOnly = PreferencesHelper.loadGpsOnly()
device_id = PreferencesHelper.load_device_id() device_id = PreferencesHelper.load_device_id()
track = Track(trackbook.database, device_id, start_time=GregorianCalendar.getInstance().time, stop_time=Date(GregorianCalendar.getInstance().time.time + 86400))
useImperial = PreferencesHelper.loadUseImperialUnits() useImperial = PreferencesHelper.loadUseImperialUnits()
omitRests = PreferencesHelper.loadOmitRests() omitRests = PreferencesHelper.loadOmitRests()
commitInterval = PreferencesHelper.loadCommitInterval() commitInterval = PreferencesHelper.loadCommitInterval()
@ -445,11 +441,11 @@ class TrackerService: Service(), SensorEventListener
return false return false
} }
} }
if (track.trkpts.isEmpty()) if (recent_trkpts.isEmpty())
{ {
return true return true
} }
if (! isDifferentEnough(track.trkpts.last().toLocation(), location, omitRests)) if (! isDifferentEnough(recent_trkpts.last().toLocation(), location, omitRests))
{ {
Log.i("VOUSSOIR", "Omitting due to too close to previous.") Log.i("VOUSSOIR", "Omitting due to too close to previous.")
return false return false
@ -466,11 +462,11 @@ class TrackerService: Service(), SensorEventListener
if (should_keep_point((currentBestLocation))) if (should_keep_point((currentBestLocation)))
{ {
trackbook.database.insert_trkpt(device_id, trkpt) trackbook.database.insert_trkpt(device_id, trkpt)
track.trkpts.add(trkpt) recent_trkpts.add(trkpt)
while (track.trkpts.size > 7200) while (recent_trkpts.size > RECENT_TRKPT_COUNT)
{ {
track.trkpts.removeFirst() recent_trkpts.removeFirst()
} }
if (now.time - lastCommit.time > Keys.SAVE_TEMP_TRACK_INTERVAL) if (now.time - lastCommit.time > Keys.SAVE_TEMP_TRACK_INTERVAL)

View File

@ -1,81 +0,0 @@
/*
* RenameTrackDialog.kt
* Implements the RenameTrackDialog class
* A RenameTrackDialog offers user to change name of track
*
* This file is part of
* TRACKBOOK - Movement Recorder for Android
*
* Copyright (c) 2016-22 - Y20K.org
* Licensed under the MIT-License
* http://opensource.org/licenses/MIT
*
* Trackbook uses osmdroid - OpenStreetMap-Tools for Android
* https://github.com/osmdroid/osmdroid
*/
package org.y20k.trackbook.dialogs
import android.content.Context
import android.text.InputType
import android.view.LayoutInflater
import android.widget.EditText
import android.widget.TextView
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.y20k.trackbook.R
import org.y20k.trackbook.helpers.LogHelper
/*
* RenameTrackDialog class
*/
class RenameTrackDialog (private var renameTrackListener: RenameTrackListener) {
/* Interface used to communicate back to activity */
interface RenameTrackListener {
fun onRenameTrackDialog(textInput: String) {
}
}
/* Define log tag */
private val TAG = LogHelper.makeLogTag(RenameTrackDialog::class.java.simpleName)
/* Construct and show dialog */
fun show(context: Context, trackName: String) {
// prepare dialog builder
val builder: MaterialAlertDialogBuilder = MaterialAlertDialogBuilder(context, R.style.AlertDialogTheme)
// get input field
val inflater = LayoutInflater.from(context)
val view = inflater.inflate(R.layout.dialog_rename_track, null)
val inputField = view.findViewById<EditText>(R.id.dialog_rename_track_input_edit_text)
// pre-fill with current track name
inputField.setText(trackName, TextView.BufferType.EDITABLE)
inputField.setSelection(trackName.length)
inputField.inputType = InputType.TYPE_CLASS_TEXT
inputField.requestFocus()
// set dialog view
builder.setView(view)
// add "add" button
builder.setPositiveButton(R.string.dialog_rename_track_button) { _, _ ->
// hand text over to initiating activity
inputField.text?.let {
var newStationName: String = it.toString()
if (newStationName.isEmpty()) newStationName = trackName
renameTrackListener.onRenameTrackDialog(newStationName)
}
}
// add cancel button
builder.setNegativeButton(R.string.dialog_generic_button_cancel) { _, _ ->
// listen for click on cancel button
// do nothing
}
// display add dialog
builder.show()
}
}

View File

@ -31,30 +31,26 @@ import org.osmdroid.views.overlay.simplefastpoint.SimpleFastPointOverlayOptions
import org.osmdroid.views.overlay.simplefastpoint.SimplePointTheme import org.osmdroid.views.overlay.simplefastpoint.SimplePointTheme
import org.y20k.trackbook.Keys import org.y20k.trackbook.Keys
import org.y20k.trackbook.R import org.y20k.trackbook.R
import org.y20k.trackbook.Track
import org.y20k.trackbook.Trkpt import org.y20k.trackbook.Trkpt
import java.text.DecimalFormat import java.text.DecimalFormat
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
/* Creates icon overlay for track */ /* Creates icon overlay for track */
fun createTrackOverlay(context: Context, map_view: MapView, track: Track, trackingState: Int) fun createTrackOverlay(context: Context, map_view: MapView, trkpts: Collection<Trkpt>, trackingState: Int)
{ {
// get marker color
val color = if (trackingState == Keys.STATE_TRACKING_ACTIVE) context.getColor(R.color.default_red) else context.getColor(R.color.default_blue) val color = if (trackingState == Keys.STATE_TRACKING_ACTIVE) context.getColor(R.color.default_red) else context.getColor(R.color.default_blue)
// gather points for overlay
val points: MutableList<IGeoPoint> = mutableListOf() val points: MutableList<IGeoPoint> = mutableListOf()
track.trkpts.forEach { wayPoint -> trkpts.forEach { trkpt ->
val label: String = "${context.getString(R.string.marker_description_time)}: ${SimpleDateFormat.getTimeInstance(SimpleDateFormat.MEDIUM, Locale.getDefault()).format(wayPoint.time)} | ${context.getString(R.string.marker_description_accuracy)}: ${DecimalFormat("#0.00").format(wayPoint.accuracy)} (${wayPoint.provider})" val label = "${context.getString(R.string.marker_description_time)}: ${SimpleDateFormat.getTimeInstance(SimpleDateFormat.MEDIUM, Locale.getDefault()).format(trkpt.time)} | ${context.getString(R.string.marker_description_accuracy)}: ${DecimalFormat("#0.00").format(trkpt.accuracy)} (${trkpt.provider})"
// only add normal points // only add normal points
if (!wayPoint.starred) if (!trkpt.starred)
{ {
points.add(LabelledGeoPoint(wayPoint.latitude, wayPoint.longitude, wayPoint.altitude, label)) points.add(LabelledGeoPoint(trkpt.latitude, trkpt.longitude, trkpt.altitude, label))
} }
} }
val pointTheme: SimplePointTheme = SimplePointTheme(points, false) val pointTheme: SimplePointTheme = SimplePointTheme(points, false)
// set styling for overlay val style = Paint()
val style: Paint = Paint()
style.style = Paint.Style.FILL style.style = Paint.Style.FILL
style.color = color style.color = color
style.flags = Paint.ANTI_ALIAS_FLAG style.flags = Paint.ANTI_ALIAS_FLAG
@ -64,20 +60,20 @@ fun createTrackOverlay(context: Context, map_view: MapView, track: Track, tracki
.setSymbol(SimpleFastPointOverlayOptions.Shape.CIRCLE) .setSymbol(SimpleFastPointOverlayOptions.Shape.CIRCLE)
.setPointStyle(style) .setPointStyle(style)
.setRadius(6F * scalingFactor) // radius is set in px - scaling factor makes that display density independent (= dp) .setRadius(6F * scalingFactor) // radius is set in px - scaling factor makes that display density independent (= dp)
.setIsClickable(true) .setIsClickable(false)
.setCellSize(12) // Sets the grid cell size used for indexing, in pixels. Larger cells result in faster rendering speed, but worse fidelity. Default is 10 pixels, for large datasets (>10k points), use 15. .setCellSize(12) // Sets the grid cell size used for indexing, in pixels. Larger cells result in faster rendering speed, but worse fidelity. Default is 10 pixels, for large datasets (>10k points), use 15.
val overlay = SimpleFastPointOverlay(pointTheme, overlayOptions) val overlay = SimpleFastPointOverlay(pointTheme, overlayOptions)
map_view.overlays.add(overlay) map_view.overlays.add(overlay)
} }
/* Creates overlay containing start, stop, stopover and starred markers for track */ /* Creates overlay containing start, stop, stopover and starred markers for track */
fun createSpecialMakersTrackOverlay(context: Context, map_view: MapView, track: Track, trackingState: Int, displayStartEndMarker: Boolean = false) fun createSpecialMakersTrackOverlay(context: Context, map_view: MapView, trkpts: Collection<Trkpt>, trackingState: Int, displayStartEndMarker: Boolean = false)
{ {
val overlayItems: ArrayList<OverlayItem> = ArrayList<OverlayItem>() val overlayItems: ArrayList<OverlayItem> = ArrayList<OverlayItem>()
val trackingActive: Boolean = trackingState == Keys.STATE_TRACKING_ACTIVE val trackingActive: Boolean = trackingState == Keys.STATE_TRACKING_ACTIVE
val maxIndex: Int = track.trkpts.size - 1 val maxIndex: Int = trkpts.size - 1
track.trkpts.forEachIndexed { index: Int, trkpt: Trkpt -> trkpts.forEachIndexed { index: Int, trkpt: Trkpt ->
var overlayItem: OverlayItem? = null var overlayItem: OverlayItem? = null
if (!trackingActive && index == 0 && displayStartEndMarker && trkpt.starred) if (!trackingActive && index == 0 && displayStartEndMarker && trkpt.starred)
{ {

View File

@ -37,18 +37,14 @@ import org.osmdroid.events.ZoomEvent
import org.osmdroid.tileprovider.tilesource.TileSourceFactory import org.osmdroid.tileprovider.tilesource.TileSourceFactory
import org.osmdroid.util.GeoPoint import org.osmdroid.util.GeoPoint
import org.osmdroid.views.MapView 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.TilesOverlay
import org.osmdroid.views.overlay.compass.CompassOverlay import org.osmdroid.views.overlay.compass.CompassOverlay
import org.osmdroid.views.overlay.compass.InternalCompassOrientationProvider import org.osmdroid.views.overlay.compass.InternalCompassOrientationProvider
import org.osmdroid.views.overlay.simplefastpoint.SimpleFastPointOverlay
import org.y20k.trackbook.Keys import org.y20k.trackbook.Keys
import org.y20k.trackbook.R import org.y20k.trackbook.R
import org.y20k.trackbook.Track import org.y20k.trackbook.Track
import org.y20k.trackbook.TrackStatistics import org.y20k.trackbook.TrackStatistics
import org.y20k.trackbook.helpers.* import org.y20k.trackbook.helpers.*
import kotlin.math.roundToInt
/* /*
* TrackFragmentLayoutHolder class * TrackFragmentLayoutHolder class
@ -63,9 +59,8 @@ data class TrackFragmentLayoutHolder(
{ {
/* Main class variables */ /* Main class variables */
val rootView: View val rootView: View
val shareButton: ImageButton val save_track_button: ImageButton
val deleteButton: ImageButton val deleteButton: ImageButton
val editButton: ImageButton
val trackNameView: MaterialTextView val trackNameView: MaterialTextView
private val mapView: MapView private val mapView: MapView
private var controller: IMapController private var controller: IMapController
@ -87,17 +82,15 @@ data class TrackFragmentLayoutHolder(
private val positiveElevationView: MaterialTextView private val positiveElevationView: MaterialTextView
private val negativeElevationView: MaterialTextView private val negativeElevationView: MaterialTextView
private val elevationDataViews: Group private val elevationDataViews: Group
private val trackManagementViews: Group
private val useImperialUnits: Boolean private val useImperialUnits: Boolean
/* Init block */ init
init { {
// find views // find views
rootView = inflater.inflate(R.layout.fragment_track, container, false) rootView = inflater.inflate(R.layout.fragment_track, container, false)
mapView = rootView.findViewById(R.id.map) mapView = rootView.findViewById(R.id.map)
shareButton = rootView.findViewById(R.id.save_button) save_track_button = rootView.findViewById(R.id.save_button)
deleteButton = rootView.findViewById(R.id.delete_button) deleteButton = rootView.findViewById(R.id.delete_button)
editButton = rootView.findViewById(R.id.edit_button)
trackNameView = rootView.findViewById(R.id.statistics_track_name_headline) trackNameView = rootView.findViewById(R.id.statistics_track_name_headline)
// basic map setup // basic map setup
@ -128,7 +121,6 @@ data class TrackFragmentLayoutHolder(
positiveElevationView = rootView.findViewById(R.id.statistics_data_positive_elevation) positiveElevationView = rootView.findViewById(R.id.statistics_data_positive_elevation)
negativeElevationView = rootView.findViewById(R.id.statistics_data_negative_elevation) negativeElevationView = rootView.findViewById(R.id.statistics_data_negative_elevation)
elevationDataViews = rootView.findViewById(R.id.elevation_data) elevationDataViews = rootView.findViewById(R.id.elevation_data)
trackManagementViews = rootView.findViewById(R.id.management_icons)
// get measurement unit system // get measurement unit system
useImperialUnits = PreferencesHelper.loadUseImperialUnits() useImperialUnits = PreferencesHelper.loadUseImperialUnits()
@ -146,14 +138,13 @@ data class TrackFragmentLayoutHolder(
mapView.overlays.add(compassOverlay) mapView.overlays.add(compassOverlay)
if (track.trkpts.isNotEmpty()) { if (track.trkpts.isNotEmpty()) {
createSpecialMakersTrackOverlay(context, mapView, track, Keys.STATE_TRACKING_STOPPED, displayStartEndMarker = true) createSpecialMakersTrackOverlay(context, mapView, track.trkpts, Keys.STATE_TRACKING_STOPPED, displayStartEndMarker = true)
createTrackOverlay(context, mapView, track, Keys.STATE_TRACKING_STOPPED) createTrackOverlay(context, mapView, track.trkpts, Keys.STATE_TRACKING_STOPPED)
} }
// set up and show statistics sheet // set up and show statistics sheet
statisticsSheetBehavior = BottomSheetBehavior.from<View>(statisticsSheet) statisticsSheetBehavior = BottomSheetBehavior.from<View>(statisticsSheet)
statisticsSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED statisticsSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
statisticsSheetBehavior.addBottomSheetCallback(getStatisticsSheetCallback())
setupStatisticsViews() setupStatisticsViews()
} }
@ -187,44 +178,17 @@ data class TrackFragmentLayoutHolder(
} }
/* Shows/hides the statistics sheet */ /* Shows/hides the statistics sheet */
private fun toggleStatisticsSheetVisibility() { private fun toggleStatisticsSheetVisibility()
{
when (statisticsSheetBehavior.state) { when (statisticsSheetBehavior.state) {
BottomSheetBehavior.STATE_EXPANDED -> statisticsSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED BottomSheetBehavior.STATE_EXPANDED -> statisticsSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
else -> statisticsSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED else -> statisticsSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
} }
} }
/* Defines the behavior of the statistics sheet */
private fun getStatisticsSheetCallback(): BottomSheetBehavior.BottomSheetCallback {
return object : BottomSheetBehavior.BottomSheetCallback() {
override fun onStateChanged(bottomSheet: View, newState: Int) {
when (newState) {
BottomSheetBehavior.STATE_EXPANDED -> {
trackManagementViews.isVisible = true
shareButton.isGone = true
// bottomSheet.setPadding(0,24,0,0)
}
else -> {
trackManagementViews.isGone = true
shareButton.isVisible = true
// bottomSheet.setPadding(0,0,0,0)
}
}
}
override fun onSlide(bottomSheet: View, slideOffset: Float) {
if (slideOffset < 0.125f) {
trackManagementViews.isGone = true
shareButton.isVisible = true
} else {
trackManagementViews.isVisible = true
shareButton.isGone = true
}
}
}
}
/* Overrides onZoom from MapListener */ /* Overrides onZoom from MapListener */
override fun onZoom(event: ZoomEvent?): Boolean { override fun onZoom(event: ZoomEvent?): Boolean
{
if (event == null) { if (event == null) {
return false return false
} else { } else {
@ -234,7 +198,8 @@ data class TrackFragmentLayoutHolder(
} }
/* Overrides onScroll from MapListener */ /* Overrides onScroll from MapListener */
override fun onScroll(event: ScrollEvent?): Boolean { override fun onScroll(event: ScrollEvent?): Boolean
{
if (event == null) { if (event == null) {
return false return false
} else { } else {

View File

@ -15,14 +15,6 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:constraint_referenced_ids="statistics_p_positive_elevation,statistics_data_positive_elevation,statistics_p_negative_elevation,statistics_data_negative_elevation,statistics_p_max_altitude,statistics_data_max_altitude,statistics_p_min_altitude,statistics_data_min_altitude" /> app:constraint_referenced_ids="statistics_p_positive_elevation,statistics_data_positive_elevation,statistics_p_negative_elevation,statistics_data_negative_elevation,statistics_p_max_altitude,statistics_data_max_altitude,statistics_p_min_altitude,statistics_data_min_altitude" />
<androidx.constraintlayout.widget.Group
android:id="@+id/management_icons"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:constraint_referenced_ids="delete_button,edit_button" />
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView
android:id="@+id/statistics_track_name_headline" android:id="@+id/statistics_track_name_headline"
android:layout_width="0dp" android:layout_width="0dp"
@ -35,7 +27,7 @@
android:textAppearance="@style/TextAppearance.Material3.TitleMedium" android:textAppearance="@style/TextAppearance.Material3.TitleMedium"
android:textColor="@color/text_default" android:textColor="@color/text_default"
android:textStyle="bold" android:textStyle="bold"
app:layout_constraintEnd_toStartOf="@+id/edit_button" app:layout_constraintEnd_toStartOf="@+id/delete_button"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:text="@string/sample_text_track_name" /> tools:text="@string/sample_text_track_name" />
@ -46,21 +38,10 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:backgroundTint="@color/default_transparent" android:backgroundTint="@color/default_transparent"
android:contentDescription="@string/descr_statistics_sheet_delete_button" android:contentDescription="@string/descr_statistics_sheet_delete_button"
app:layout_constraintBottom_toBottomOf="@+id/edit_button"
app:layout_constraintEnd_toStartOf="@+id/save_button"
app:layout_constraintTop_toTopOf="@+id/edit_button"
app:srcCompat="@drawable/ic_delete_24dp" />
<ImageButton
android:id="@+id/edit_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:backgroundTint="@color/default_transparent"
android:contentDescription="@string/descr_statistics_sheet_edit_button"
app:layout_constraintBottom_toBottomOf="@+id/statistics_track_name_headline" app:layout_constraintBottom_toBottomOf="@+id/statistics_track_name_headline"
app:layout_constraintEnd_toStartOf="@+id/delete_button" app:layout_constraintEnd_toStartOf="@+id/save_button"
app:layout_constraintTop_toTopOf="@+id/statistics_track_name_headline" app:layout_constraintTop_toTopOf="@+id/statistics_track_name_headline"
app:srcCompat="@drawable/ic_edit_24dp" /> app:srcCompat="@drawable/ic_delete_24dp" />
<ImageButton <ImageButton
android:id="@+id/save_button" android:id="@+id/save_button"
@ -68,7 +49,6 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:backgroundTint="@color/default_transparent" android:backgroundTint="@color/default_transparent"
android:contentDescription="@string/descr_statistics_sheet_save_button" android:contentDescription="@string/descr_statistics_sheet_save_button"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="@+id/statistics_track_name_headline" app:layout_constraintBottom_toBottomOf="@+id/statistics_track_name_headline"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/statistics_track_name_headline" app:layout_constraintTop_toTopOf="@+id/statistics_track_name_headline"

View File

@ -5,7 +5,7 @@
<!-- please do not translate app_name - transcription into different alphabet types is fine though --> <!-- please do not translate app_name - transcription into different alphabet types is fine though -->
<!-- Tabs --> <!-- Tabs -->
<string name="tab_map">Map</string> <string name="tab_map">Map</string>
<string name="tab_tracks">Tracks</string> <string name="tab_tracks">History</string>
<string name="tab_settings">Settings</string> <string name="tab_settings">Settings</string>
<!-- Notification --> <!-- Notification -->
<string name="notification_title_trackbook_running">Trackbook running</string> <string name="notification_title_trackbook_running">Trackbook running</string>