From 7956f44ce406946b1f9d54826818da7947479b0e Mon Sep 17 00:00:00 2001 From: Ethan Dalool Date: Sat, 4 Mar 2023 21:29:18 -0800 Subject: [PATCH] Was experimenting with automatic GPX export. Hardcoded path. These changes are several months old, I am just now committing them because I want to move on to a different experiment. --- app/src/main/AndroidManifest.xml | 6 +- app/src/main/java/org/y20k/trackbook/Keys.kt | 18 ++-- .../java/org/y20k/trackbook/MainActivity.kt | 35 +++++++- .../java/org/y20k/trackbook/MapFragment.kt | 6 +- .../org/y20k/trackbook/SettingsFragment.kt | 11 +++ .../java/org/y20k/trackbook/TrackFragment.kt | 16 +++- .../java/org/y20k/trackbook/TrackerService.kt | 65 +++++++++----- .../java/org/y20k/trackbook/core/Track.kt | 56 ++++++++++-- .../org/y20k/trackbook/helpers/FileHelper.kt | 5 +- .../trackbook/helpers/PreferencesHelper.kt | 6 +- .../org/y20k/trackbook/helpers/TrackHelper.kt | 4 - .../org/y20k/trackbook/helpers/UiHelper.kt | 1 - .../trackbook/tracklist/TracklistAdapter.kt | 89 ++++++------------- .../trackbook/ui/TrackFragmentLayoutHolder.kt | 2 +- app/src/main/res/values/strings.xml | 4 +- 15 files changed, 204 insertions(+), 120 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d2b23a3..1df00a4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,8 @@ + + @@ -17,13 +19,15 @@ - + + diff --git a/app/src/main/java/org/y20k/trackbook/Keys.kt b/app/src/main/java/org/y20k/trackbook/Keys.kt index 0ffdcec..7159656 100644 --- a/app/src/main/java/org/y20k/trackbook/Keys.kt +++ b/app/src/main/java/org/y20k/trackbook/Keys.kt @@ -57,6 +57,7 @@ object Keys { const val PREF_USE_IMPERIAL_UNITS: String = "prefUseImperialUnits" const val PREF_GPS_ONLY: String = "prefGpsOnly" const val PREF_OMIT_RESTS: String = "prefOmitRests" + const val PREF_AUTO_EXPORT_INTERVAL: String = "prefAutoExportInterval" const val PREF_ALTITUDE_SMOOTHING_VALUE: String = "prefAltitudeSmoothingValue" const val PREF_LOCATION_ACCURACY_THRESHOLD: String = "prefLocationAccuracyThreshold" const val PREF_LOCATION_AGE_THRESHOLD: String = "prefLocationAgeThreshold" @@ -99,22 +100,25 @@ object Keys { // default values val DEFAULT_DATE: Date = Date(0L) const val DEFAULT_RFC2822_DATE: String = "Thu, 01 Jan 1970 01:00:00 +0100" // --> Date(0) - const val ONE_HOUR_IN_MILLISECONDS: Int = 3600000 + const val ONE_SECOND_IN_MILLISECONDS: Long = 1000 + const val ONE_MINUTE_IN_MILLISECONDS: Long = 60 * ONE_SECOND_IN_MILLISECONDS + const val ONE_HOUR_IN_MILLISECONDS: Long = 60 * ONE_MINUTE_IN_MILLISECONDS const val EMPTY_STRING_RESOURCE: Int = 0 - const val REQUEST_CURRENT_LOCATION_INTERVAL: Long = 1000L // 1 second in milliseconds - const val ADD_WAYPOINT_TO_TRACK_INTERVAL: Long = 1000L // 1 second in milliseconds - const val SAVE_TEMP_TRACK_INTERVAL: Long = 9000L // 9 seconds in milliseconds - const val SIGNIFICANT_TIME_DIFFERENCE: Long = 120000L // 2 minutes in milliseconds - const val STOP_OVER_THRESHOLD: Long = 300000L // 5 minutes in milliseconds + const val REQUEST_CURRENT_LOCATION_INTERVAL: Long = 1 * ONE_SECOND_IN_MILLISECONDS + const val ADD_WAYPOINT_TO_TRACK_INTERVAL: Long = 1 * ONE_SECOND_IN_MILLISECONDS + const val SAVE_TEMP_TRACK_INTERVAL: Long = 30 * ONE_SECOND_IN_MILLISECONDS + const val SIGNIFICANT_TIME_DIFFERENCE: Long = 2 * ONE_MINUTE_IN_MILLISECONDS + const val STOP_OVER_THRESHOLD: Long = 5 * ONE_MINUTE_IN_MILLISECONDS const val IMPLAUSIBLE_TRACK_START_SPEED: Double = 250.0 // 250 km/h const val DEFAULT_LATITUDE: Double = 71.172500 // latitude Nordkapp, Norway const val DEFAULT_LONGITUDE: Double = 25.784444 // longitude Nordkapp, Norway const val DEFAULT_ACCURACY: Float = 300f // in meters const val DEFAULT_ALTITUDE: Double = 0.0 const val DEFAULT_TIME: Long = 0L + const val DEFAULT_AUTO_EXPORT_INTERVAL: Int = 24 const val DEFAULT_ALTITUDE_SMOOTHING_VALUE: Int = 13 const val DEFAULT_THRESHOLD_LOCATION_ACCURACY: Int = 30 // 30 meters - const val DEFAULT_THRESHOLD_LOCATION_AGE: Long = 60000000000L // one minute in nanoseconds + const val DEFAULT_THRESHOLD_LOCATION_AGE: Long = 60_000_000_000L // one minute in nanoseconds const val DEFAULT_THRESHOLD_DISTANCE: Float = 15f // 15 meters const val DEFAULT_ZOOM_LEVEL: Double = 16.0 const val MIN_NUMBER_OF_WAYPOINTS_FOR_ELEVATION_CALCULATION: Int = 5 diff --git a/app/src/main/java/org/y20k/trackbook/MainActivity.kt b/app/src/main/java/org/y20k/trackbook/MainActivity.kt index 834b708..ea51654 100644 --- a/app/src/main/java/org/y20k/trackbook/MainActivity.kt +++ b/app/src/main/java/org/y20k/trackbook/MainActivity.kt @@ -17,12 +17,16 @@ package org.y20k.trackbook +import android.Manifest +import android.app.Activity import android.content.SharedPreferences +import android.content.pm.PackageManager import android.os.Build import android.os.Bundle import android.os.StrictMode import android.os.StrictMode.VmPolicy import androidx.appcompat.app.AppCompatActivity +import androidx.core.app.ActivityCompat import androidx.navigation.fragment.NavHostFragment import androidx.navigation.ui.setupWithNavController import com.google.android.material.bottomnavigation.BottomNavigationView @@ -31,6 +35,35 @@ import org.y20k.trackbook.helpers.AppThemeHelper import org.y20k.trackbook.helpers.LogHelper import org.y20k.trackbook.helpers.PreferencesHelper +private const val REQUEST_EXTERNAL_STORAGE = 1 +private val PERMISSIONS_STORAGE = arrayOf( + Manifest.permission.READ_EXTERNAL_STORAGE, + Manifest.permission.WRITE_EXTERNAL_STORAGE +) + +/** + * Checks if the app has permission to write to device storage + * + * If the app does not has permission then the user will be prompted to grant permissions + * + * @param activity + */ +fun verifyStoragePermissions(activity: Activity?) +{ + // Check if we have write permission + val permission = ActivityCompat.checkSelfPermission(activity!!, + Manifest.permission.WRITE_EXTERNAL_STORAGE) + if (permission != PackageManager.PERMISSION_GRANTED) + { + // We don't have permission so prompt the user + ActivityCompat.requestPermissions( + activity, + PERMISSIONS_STORAGE, + REQUEST_EXTERNAL_STORAGE + ) + } +} + /* * MainActivity class */ @@ -48,7 +81,7 @@ class MainActivity : AppCompatActivity() { /* Overrides onCreate from AppCompatActivity */ override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - + verifyStoragePermissions(this) // todo: remove after testing finished if (BuildConfig.DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { StrictMode.setVmPolicy( diff --git a/app/src/main/java/org/y20k/trackbook/MapFragment.kt b/app/src/main/java/org/y20k/trackbook/MapFragment.kt index 4b554b7..1926a9d 100644 --- a/app/src/main/java/org/y20k/trackbook/MapFragment.kt +++ b/app/src/main/java/org/y20k/trackbook/MapFragment.kt @@ -275,7 +275,7 @@ class MapFragment : Fragment(), YesNoDialog.YesNoDialogListener, MapOverlayHelpe private fun handleTrackingManagementMenu() { when (trackingState) { Keys.STATE_TRACKING_PAUSED -> resumeTracking() - Keys.STATE_TRACKING_ACTIVE -> trackerService.stopTracking() + Keys.STATE_TRACKING_ACTIVE -> trackerService.pauseTracking() Keys.STATE_TRACKING_NOT_STARTED -> startTracking() } } @@ -296,9 +296,7 @@ class MapFragment : Fragment(), YesNoDialog.YesNoDialogListener, MapOverlayHelpe else { CoroutineScope(IO).launch { - track.save_json(activity as Context) - track.save_gpx(activity as Context) - trackerService.clearTrack() + trackerService.saveTrackAndClear(activity as Context) withContext(Main) { // step 4: open track in TrackFragement openTrack(track) diff --git a/app/src/main/java/org/y20k/trackbook/SettingsFragment.kt b/app/src/main/java/org/y20k/trackbook/SettingsFragment.kt index 908e546..4616c8a 100644 --- a/app/src/main/java/org/y20k/trackbook/SettingsFragment.kt +++ b/app/src/main/java/org/y20k/trackbook/SettingsFragment.kt @@ -123,6 +123,16 @@ class SettingsFragment : PreferenceFragmentCompat(), YesNoDialog.YesNoDialogList preferenceOmitRests.summaryOff = getString(R.string.pref_omit_rests_off) preferenceOmitRests.setDefaultValue(DEFAULT_OMIT_RESTS) + val preferenceAutoExportInterval: SeekBarPreference = SeekBarPreference(activity as Context) + preferenceAutoExportInterval.title = getString(R.string.pref_auto_export_interval_title) + preferenceAutoExportInterval.setIcon(R.drawable.ic_bar_chart_24) + preferenceAutoExportInterval.key = Keys.PREF_AUTO_EXPORT_INTERVAL + preferenceAutoExportInterval.summary = getString(R.string.pref_auto_export_interval_summary) + preferenceAutoExportInterval.showSeekBarValue = true + preferenceAutoExportInterval.min = 1 + preferenceAutoExportInterval.max = 24 + preferenceAutoExportInterval.setDefaultValue(Keys.DEFAULT_ALTITUDE_SMOOTHING_VALUE) + // set up "Altitude Smoothing" preference // val preferenceAltitudeSmoothingValue: SeekBarPreference = SeekBarPreference(activity as Context) // preferenceAltitudeSmoothingValue.title = getString(R.string.pref_altitude_smoothing_value_title) @@ -190,6 +200,7 @@ class SettingsFragment : PreferenceFragmentCompat(), YesNoDialog.YesNoDialogList screen.addPreference(preferenceCategoryAdvanced) screen.addPreference(preferenceOmitRests) // screen.addPreference(preferenceAltitudeSmoothingValue) + screen.addPreference(preferenceAutoExportInterval) screen.addPreference(preferenceResetAdvanced) screen.addPreference(preferenceCategoryAbout) screen.addPreference(preferenceAppVersion) diff --git a/app/src/main/java/org/y20k/trackbook/TrackFragment.kt b/app/src/main/java/org/y20k/trackbook/TrackFragment.kt index 6929d45..6c16f8c 100644 --- a/app/src/main/java/org/y20k/trackbook/TrackFragment.kt +++ b/app/src/main/java/org/y20k/trackbook/TrackFragment.kt @@ -49,7 +49,7 @@ import org.y20k.trackbook.helpers.LogHelper import org.y20k.trackbook.helpers.MapOverlayHelper import org.y20k.trackbook.helpers.TrackHelper import org.y20k.trackbook.ui.TrackFragmentLayoutHolder - +import java.io.File class TrackFragment : Fragment(), RenameTrackDialog.RenameTrackListener, YesNoDialog.YesNoDialogListener, MapOverlayHelper.MarkerListener { @@ -138,6 +138,7 @@ class TrackFragment : Fragment(), RenameTrackDialog.RenameTrackListener, YesNoDi if (result.resultCode == Activity.RESULT_OK && result.data != null) { val sourceUri: Uri = layout.track.get_gpx_file(activity as Context).toUri() + Toast.makeText(activity as Context, sourceUri.toString(), Toast.LENGTH_LONG).show() val targetUri: Uri? = result.data?.data if (targetUri != null) { @@ -145,7 +146,8 @@ class TrackFragment : Fragment(), RenameTrackDialog.RenameTrackListener, YesNoDi CoroutineScope(Dispatchers.IO).launch { FileHelper.saveCopyOfFileSuspended(activity as Context, originalFileUri = sourceUri, targetFileUri = targetUri) } - Toast.makeText(activity as Context, R.string.toast_message_save_gpx, Toast.LENGTH_LONG).show() + Toast.makeText(activity as Context, targetUri.toString(), Toast.LENGTH_LONG).show() + // Toast.makeText(activity as Context, R.string.toast_message_save_gpx, Toast.LENGTH_LONG).show() } } } @@ -211,6 +213,16 @@ class TrackFragment : Fragment(), RenameTrackDialog.RenameTrackListener, YesNoDi LogHelper.e(TAG, "Unable to save GPX.") Toast.makeText(activity as Context, R.string.toast_message_install_file_helper, Toast.LENGTH_LONG).show() } + // val context = this.activity as Context + // val export_name: String = DateTimeHelper.convertToSortableDateString(layout.track.recordingStart) + Keys.GPX_FILE_EXTENSION + // val sourceUri: Uri = layout.track.get_gpx_file(activity as Context).toUri() + // // val targetUri: Uri = "file:///storage/emulated/0/Syncthing/GPX".toUri() + // val targetUri: Uri = File(File("/storage/emulated/0/Syncthing/GPX"), export_name).toUri() + // Toast.makeText(activity as Context, targetUri.toString(), Toast.LENGTH_LONG).show() + // CoroutineScope(Dispatchers.IO).launch { + // FileHelper.saveCopyOfFileSuspended(activity as Context, originalFileUri = sourceUri, targetFileUri = targetUri) + // } + // Toast.makeText(activity as Context, R.string.toast_message_save_gpx, Toast.LENGTH_LONG).show() } diff --git a/app/src/main/java/org/y20k/trackbook/TrackerService.kt b/app/src/main/java/org/y20k/trackbook/TrackerService.kt index b43e305..62979ba 100644 --- a/app/src/main/java/org/y20k/trackbook/TrackerService.kt +++ b/app/src/main/java/org/y20k/trackbook/TrackerService.kt @@ -58,12 +58,11 @@ class TrackerService: Service(), SensorEventListener var useImperial: Boolean = false var gpsOnly: Boolean = false var omitRests: Boolean = true + var autoExportInterval: Int = Keys.DEFAULT_AUTO_EXPORT_INTERVAL var currentBestLocation: Location = LocationHelper.getDefaultLocation() - var lastSave: Date = Keys.DEFAULT_DATE + var lastTempSave: Date = Keys.DEFAULT_DATE + var lastAutoExport: Date = Keys.DEFAULT_DATE var stepCountOffset: Float = 0f - // The resumed flag will be true for the first point that is received after unpausing a - // recording, so that the distance travelled while paused is not added to the track.distance. - var resumed: Boolean = false var track: Track = Track() var gpsLocationListenerRegistered: Boolean = false var networkLocationListenerRegistered: Boolean = false @@ -152,7 +151,7 @@ class TrackerService: Service(), SensorEventListener fun clearTrack() { track = Track() - resumed = false + stepCountOffset = 0f FileHelper.delete_temp_file(this as Context) trackingState = Keys.STATE_TRACKING_NOT_STARTED PreferencesHelper.saveTrackingState(trackingState) @@ -237,6 +236,7 @@ class TrackerService: Service(), SensorEventListener gpsOnly = PreferencesHelper.loadGpsOnly() useImperial = PreferencesHelper.loadUseImperialUnits() omitRests = PreferencesHelper.loadOmitRests() + autoExportInterval = PreferencesHelper.loadAutoExportInterval() locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager sensorManager = this.getSystemService(Context.SENSOR_SERVICE) as SensorManager @@ -259,7 +259,7 @@ class TrackerService: Service(), SensorEventListener LogHelper.i(TAG, "onDestroy called.") if (trackingState == Keys.STATE_TRACKING_ACTIVE) { - stopTracking() + pauseTracking() } stopForeground(true) notificationManager.cancel(Keys.TRACKER_SERVICE_NOTIFICATION_ID) // this call was not necessary prior to Android 12 @@ -305,7 +305,7 @@ class TrackerService: Service(), SensorEventListener } else if (intent.action == Keys.ACTION_STOP) { - stopTracking() + pauseTracking() } else if (intent.action == Keys.ACTION_START) { @@ -363,17 +363,31 @@ class TrackerService: Service(), SensorEventListener { // load temp track - returns an empty track if there is no temp file. track = load_temp_track(this) - // try to mark last waypoint as stopover - if (track.wayPoints.size > 0) { - val lastWayPointIndex = track.wayPoints.size - 1 - track.wayPoints[lastWayPointIndex].isStopOver = true + if (track.wayPoints.isNotEmpty()) { + track.wayPoints.last().isStopOver = true } - resumed = true - // calculate length of recording break - track.recordingPaused += TrackHelper.calculateDurationOfPause(track.recordingStop) + track.resumed = true + track.recordingPaused += (GregorianCalendar.getInstance().time.time - track.recordingStop.time) startTracking(newTrack = false) } + fun saveTrackAndClear(context: Context) + { + this.pauseTracking() + track.save_all_files(context) + this.clearTrack() + } + + fun saveTrackAndStartNew(context: Context) + { + if (track.wayPoints.isNotEmpty()) + { + track.save_all_files(context) + } + track = Track() + FileHelper.delete_temp_file(this as Context) + } + private fun startStepCounter() { val stepCounterAvailable = sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER), SensorManager.SENSOR_DELAY_UI) @@ -390,7 +404,6 @@ class TrackerService: Service(), SensorEventListener // set up new track if (newTrack) { track = Track() - resumed = false stepCountOffset = 0f } trackingState = Keys.STATE_TRACKING_ACTIVE @@ -400,11 +413,10 @@ class TrackerService: Service(), SensorEventListener startForeground(Keys.TRACKER_SERVICE_NOTIFICATION_ID, displayNotification()) } - fun stopTracking() + fun pauseTracking() { track.recordingStop = GregorianCalendar.getInstance().time - val context: Context = this - CoroutineScope(IO).launch { track.save_temp_suspended(context) } + CoroutineScope(IO).launch { track.save_temp_suspended(this@TrackerService) } trackingState = Keys.STATE_TRACKING_PAUSED PreferencesHelper.saveTrackingState(trackingState) @@ -439,6 +451,9 @@ class TrackerService: Service(), SensorEventListener Keys.PREF_OMIT_RESTS -> { omitRests = PreferencesHelper.loadOmitRests() } + Keys.PREF_AUTO_EXPORT_INTERVAL -> { + autoExportInterval = PreferencesHelper.loadAutoExportInterval() + } } } /* @@ -462,9 +477,10 @@ class TrackerService: Service(), SensorEventListener { override fun run() { // add waypoint to track - step count is continuously updated in onSensorChanged - val success = track.add_waypoint(currentBestLocation, omitRests, resumed) + val success = track.add_waypoint(currentBestLocation, omitRests, track.resumed) + val now: Date = GregorianCalendar.getInstance().time if (success) { - resumed = false + track.resumed = false // store previous smoothed altitude val previousAltitude: Double = altitudeValues.getAverage() @@ -488,11 +504,14 @@ class TrackerService: Service(), SensorEventListener } // save a temp track - val now: Date = GregorianCalendar.getInstance().time - if (now.time - lastSave.time > Keys.SAVE_TEMP_TRACK_INTERVAL) { - lastSave = now + if (now.time - lastTempSave.time > Keys.SAVE_TEMP_TRACK_INTERVAL) { + lastTempSave = now CoroutineScope(IO).launch { track.save_temp_suspended(this@TrackerService) } } + + } + if (now.time - track.recordingStart.time > (autoExportInterval * Keys.ONE_HOUR_IN_MILLISECONDS)) { + saveTrackAndStartNew(this@TrackerService) } // update notification displayNotification() diff --git a/app/src/main/java/org/y20k/trackbook/core/Track.kt b/app/src/main/java/org/y20k/trackbook/core/Track.kt index 1301861..8917fce 100644 --- a/app/src/main/java/org/y20k/trackbook/core/Track.kt +++ b/app/src/main/java/org/y20k/trackbook/core/Track.kt @@ -16,23 +16,36 @@ package org.y20k.trackbook.core +import android.Manifest +import android.app.Activity import android.content.Context +import android.content.pm.PackageManager import android.location.Location +import android.net.Uri +import android.os.Handler +import android.os.Looper import android.os.Parcelable import android.util.Log +import android.widget.Toast import androidx.annotation.Keep +import androidx.core.app.ActivityCompat +import androidx.core.net.toUri import com.google.gson.annotations.Expose +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.parcelize.Parcelize +import org.y20k.trackbook.Keys +import org.y20k.trackbook.R +import org.y20k.trackbook.helpers.DateTimeHelper +import org.y20k.trackbook.helpers.FileHelper +import org.y20k.trackbook.helpers.LocationHelper import java.io.File import java.text.SimpleDateFormat import java.util.* import kotlin.coroutines.resume import kotlin.coroutines.suspendCoroutine import kotlin.random.Random -import kotlinx.parcelize.Parcelize -import org.y20k.trackbook.Keys -import org.y20k.trackbook.helpers.DateTimeHelper -import org.y20k.trackbook.helpers.FileHelper -import org.y20k.trackbook.helpers.LocationHelper /* * Track data class @@ -50,6 +63,9 @@ data class Track ( @Expose var recordingStart: Date = GregorianCalendar.getInstance().time, @Expose var dateString: String = DateTimeHelper.convertToReadableDate(recordingStart), @Expose var recordingStop: Date = recordingStart, + // The resumed flag will be true for the first point that is received after unpausing a + // recording, so that the distance travelled while paused is not added to the track.distance. + @Expose var resumed: Boolean = false, @Expose var maxAltitude: Double = 0.0, @Expose var minAltitude: Double = 0.0, @Expose var positiveElevation: Double = 0.0, @@ -165,22 +181,29 @@ data class Track ( return File(context.getExternalFilesDir(Keys.FOLDER_GPX), basename) } + fun get_export_gpx_file(context: Context): File + { + val basename: String = DateTimeHelper.convertToSortableDateString(this.recordingStart) + Keys.GPX_FILE_EXTENSION + return File(File("/storage/emulated/0/Syncthing/GPX"), basename) + } + fun get_json_file(context: Context): File { val basename: String = this.id.toString() + Keys.TRACKBOOK_FILE_EXTENSION return File(context.getExternalFilesDir(Keys.FOLDER_TRACKS), basename) } - fun save_both(context: Context) + fun save_all_files(context: Context) { this.save_json(context) this.save_gpx(context) + this.save_export_gpx(context) } - suspend fun save_both_suspended(context: Context) + suspend fun save_all_files_suspended(context: Context) { return suspendCoroutine { cont -> - cont.resume(this.save_both(context)) + cont.resume(this.save_all_files(context)) } } @@ -198,6 +221,23 @@ data class Track ( } } + fun save_export_gpx(context: Context) + { + val gpx: String = this.to_gpx() + val outputfile: File = this.get_export_gpx_file(context) + FileHelper.write_text_file_noblank(gpx, outputfile) + Handler(Looper.getMainLooper()).post { + Toast.makeText(context, outputfile.toString(), Toast.LENGTH_SHORT).show() + } + } + + suspend fun save_export_gpx_suspended(context: Context) + { + return suspendCoroutine { cont -> + cont.resume(this.save_export_gpx(context)) + } + } + fun save_json(context: Context) { val json: String = this.to_json() diff --git a/app/src/main/java/org/y20k/trackbook/helpers/FileHelper.kt b/app/src/main/java/org/y20k/trackbook/helpers/FileHelper.kt index 3c79d45..7d19ccb 100644 --- a/app/src/main/java/org/y20k/trackbook/helpers/FileHelper.kt +++ b/app/src/main/java/org/y20k/trackbook/helpers/FileHelper.kt @@ -55,7 +55,8 @@ object FileHelper { suspend fun renameTrackSuspended(context: Context, track: Track, newName: String) { return suspendCoroutine { cont -> track.name = newName - track.save_both(context) + track.save_json(context) + track.save_gpx(context) cont.resume(Unit) } } @@ -71,7 +72,7 @@ object FileHelper { /* Copies file to specified target */ - private fun copyFile(context: Context, originalFileUri: Uri, targetFileUri: Uri, deleteOriginal: Boolean = false) { + fun copyFile(context: Context, originalFileUri: Uri, targetFileUri: Uri, deleteOriginal: Boolean = false) { val inputStream = context.contentResolver.openInputStream(originalFileUri) val outputStream = context.contentResolver.openOutputStream(targetFileUri) if (outputStream != null) { diff --git a/app/src/main/java/org/y20k/trackbook/helpers/PreferencesHelper.kt b/app/src/main/java/org/y20k/trackbook/helpers/PreferencesHelper.kt index 232ab26..dec7997 100644 --- a/app/src/main/java/org/y20k/trackbook/helpers/PreferencesHelper.kt +++ b/app/src/main/java/org/y20k/trackbook/helpers/PreferencesHelper.kt @@ -71,9 +71,11 @@ object PreferencesHelper { return sharedPreferences.getBoolean(Keys.PREF_OMIT_RESTS, true) } -// /* Load altitude smoothing value */ + fun loadAutoExportInterval(): Int { + return sharedPreferences.getInt(Keys.PREF_AUTO_EXPORT_INTERVAL, Keys.DEFAULT_AUTO_EXPORT_INTERVAL) + } + // fun loadAltitudeSmoothingValue(): Int { -// // load current setting // return sharedPreferences.getInt(Keys.PREF_ALTITUDE_SMOOTHING_VALUE, Keys.DEFAULT_ALTITUDE_SMOOTHING_VALUE) // } diff --git a/app/src/main/java/org/y20k/trackbook/helpers/TrackHelper.kt b/app/src/main/java/org/y20k/trackbook/helpers/TrackHelper.kt index 0e0d098..9925584 100644 --- a/app/src/main/java/org/y20k/trackbook/helpers/TrackHelper.kt +++ b/app/src/main/java/org/y20k/trackbook/helpers/TrackHelper.kt @@ -32,10 +32,6 @@ object TrackHelper { /* Adds given locatiom as waypoint to track */ - - /* Calculates time passed since last stop of recording */ - fun calculateDurationOfPause(recordingStop: Date): Long = GregorianCalendar.getInstance().time.time - recordingStop.time - /* Toggles starred flag for given position */ fun toggle_waypoint_starred(context: Context, track: Track, latitude: Double, longitude: Double) { diff --git a/app/src/main/java/org/y20k/trackbook/helpers/UiHelper.kt b/app/src/main/java/org/y20k/trackbook/helpers/UiHelper.kt index 42af3f2..f1af4fc 100644 --- a/app/src/main/java/org/y20k/trackbook/helpers/UiHelper.kt +++ b/app/src/main/java/org/y20k/trackbook/helpers/UiHelper.kt @@ -104,7 +104,6 @@ object UiHelper { override fun getSwipeDirs(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int { // disable swipe for statistics element - if (viewHolder is TracklistAdapter.ElementStatisticsViewHolder) return 0 return super.getSwipeDirs(recyclerView, viewHolder) } diff --git a/app/src/main/java/org/y20k/trackbook/tracklist/TracklistAdapter.kt b/app/src/main/java/org/y20k/trackbook/tracklist/TracklistAdapter.kt index 5b196f5..7a4cf72 100644 --- a/app/src/main/java/org/y20k/trackbook/tracklist/TracklistAdapter.kt +++ b/app/src/main/java/org/y20k/trackbook/tracklist/TracklistAdapter.kt @@ -75,64 +75,39 @@ class TracklistAdapter(private val fragment: Fragment) : RecyclerView.Adapter { - val v = LayoutInflater.from(parent.context).inflate(R.layout.element_statistics, parent, false) - return ElementStatisticsViewHolder(v) - } - else -> { - val v = LayoutInflater.from(parent.context).inflate(R.layout.element_track, parent, false) - return ElementTrackViewHolder(v) - } - } + val v = LayoutInflater.from(parent.context).inflate(R.layout.element_track, parent, false) + return ElementTrackViewHolder(v) } /* Overrides getItemViewType */ override fun getItemViewType(position: Int): Int { - if (position == 0) { - return Keys.VIEW_TYPE_STATISTICS - } else { - return Keys.VIEW_TYPE_TRACK - } + return Keys.VIEW_TYPE_TRACK } /* Overrides getItemCount from RecyclerView.Adapter */ override fun getItemCount(): Int { - // +1 because of the total statistics element - return tracklist.tracks.size + 1 + return tracklist.tracks.size } /* Overrides onBindViewHolder from RecyclerView.Adapter */ override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { - when (holder) - { - // CASE STATISTICS ELEMENT - is ElementStatisticsViewHolder -> { - val elementStatisticsViewHolder: ElementStatisticsViewHolder = holder - elementStatisticsViewHolder.totalDistanceView.text = LengthUnitHelper.convertDistanceToString(tracklist.get_total_distance(), useImperial) - } - - // CASE TRACK ELEMENT - is ElementTrackViewHolder -> { - val positionInTracklist: Int = position - 1 // Element 0 is the statistics element. - val elementTrackViewHolder: ElementTrackViewHolder = holder - elementTrackViewHolder.trackNameView.text = tracklist.tracks[positionInTracklist].name - elementTrackViewHolder.trackDataView.text = createTrackDataString(positionInTracklist) - when (tracklist.tracks[positionInTracklist].starred) { - true -> elementTrackViewHolder.starButton.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_star_filled_24dp)) - false -> elementTrackViewHolder.starButton.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_star_outline_24dp)) - } - elementTrackViewHolder.trackElement.setOnClickListener { - tracklistListener.onTrackElementTapped(tracklist.tracks[positionInTracklist]) - } - elementTrackViewHolder.starButton.setOnClickListener { - toggleStarred(it, positionInTracklist) - } - } + val positionInTracklist: Int = position + val elementTrackViewHolder: ElementTrackViewHolder = holder as ElementTrackViewHolder + elementTrackViewHolder.trackNameView.text = tracklist.tracks[positionInTracklist].name + elementTrackViewHolder.trackDataView.text = createTrackDataString(positionInTracklist) + when (tracklist.tracks[positionInTracklist].starred) { + true -> elementTrackViewHolder.starButton.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_star_filled_24dp)) + false -> elementTrackViewHolder.starButton.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_star_outline_24dp)) + } + elementTrackViewHolder.trackElement.setOnClickListener { + tracklistListener.onTrackElementTapped(tracklist.tracks[positionInTracklist]) + } + elementTrackViewHolder.starButton.setOnClickListener { + toggleStarred(it, positionInTracklist) } } @@ -140,18 +115,16 @@ class TracklistAdapter(private val fragment: Fragment) : RecyclerView.AdapterAccuracy Threshold Number of waypoints used to smooth the elevation curve. Altitude Smoothing + Automatically export GPX file after this many hours. + Auto Export Interval Advanced Delete all recordings in \"Tracks\" that are not starred. Delete Non-Starred Recordings @@ -98,7 +100,7 @@ Use Imperial Measurements Waypoints will not be recorded if they are too close to the previous waypoint. All waypoints will be recorded, even while standing still. - Omit points during rests + Omit repeated points Report bugs and suggest improvements on GitHub. Report Issue Reset advanced settings to defaults.