removes the Smothing slider (see #99) & added a "Total Distance Recorded" info at the top of the list of recordings
This commit is contained in:
parent
a9ecdcc3ab
commit
d22638da92
17 changed files with 213 additions and 109 deletions
|
@ -58,18 +58,18 @@ dependencies {
|
||||||
|
|
||||||
// AndroidX
|
// AndroidX
|
||||||
def navigationVersion = "2.3.5"
|
def navigationVersion = "2.3.5"
|
||||||
implementation "androidx.activity:activity-ktx:1.2.3"
|
implementation "androidx.activity:activity-ktx:1.3.1"
|
||||||
implementation 'androidx.appcompat:appcompat:1.3.0'
|
implementation 'androidx.appcompat:appcompat:1.3.1'
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
|
implementation 'androidx.constraintlayout:constraintlayout:2.1.0'
|
||||||
implementation 'androidx.core:core-ktx:1.5.0'
|
implementation 'androidx.core:core-ktx:1.6.0'
|
||||||
implementation "androidx.navigation:navigation-fragment-ktx:$navigationVersion"
|
implementation "androidx.navigation:navigation-fragment-ktx:$navigationVersion"
|
||||||
implementation "androidx.navigation:navigation-ui-ktx:$navigationVersion"
|
implementation "androidx.navigation:navigation-ui-ktx:$navigationVersion"
|
||||||
implementation 'androidx.preference:preference-ktx:1.1.1'
|
implementation 'androidx.preference:preference-ktx:1.1.1'
|
||||||
implementation 'com.google.android.material:material:1.3.0'
|
implementation 'com.google.android.material:material:1.4.0'
|
||||||
|
|
||||||
// Gson
|
// Gson
|
||||||
implementation 'com.google.code.gson:gson:2.8.7'
|
implementation 'com.google.code.gson:gson:2.8.8'
|
||||||
|
|
||||||
// OpenStreetMap
|
// OpenStreetMap
|
||||||
implementation 'org.osmdroid:osmdroid-android:6.1.10'
|
implementation 'org.osmdroid:osmdroid-android:6.1.11'
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,6 +91,9 @@ object Keys {
|
||||||
const val TEMP_FILE: String = "temp.json"
|
const val TEMP_FILE: String = "temp.json"
|
||||||
const val TRACKLIST_FILE: String = "tracklist.json"
|
const val TRACKLIST_FILE: String = "tracklist.json"
|
||||||
|
|
||||||
|
// view types
|
||||||
|
const val VIEW_TYPE_STATISTICS: Int = 1
|
||||||
|
const val VIEW_TYPE_TRACK: Int = 2
|
||||||
|
|
||||||
// default values
|
// default values
|
||||||
val DEFAULT_DATE: Date = Date(0L)
|
val DEFAULT_DATE: Date = Date(0L)
|
||||||
|
@ -108,7 +111,7 @@ object Keys {
|
||||||
const val DEFAULT_ACCURACY: Float = 300f // in meters
|
const val DEFAULT_ACCURACY: Float = 300f // in meters
|
||||||
const val DEFAULT_ALTITUDE: Double = 0.0
|
const val DEFAULT_ALTITUDE: Double = 0.0
|
||||||
const val DEFAULT_TIME: Long = 0L
|
const val DEFAULT_TIME: Long = 0L
|
||||||
const val DEFAULT_ALTITUDE_SMOOTHING_VALUE: Int = 10
|
const val DEFAULT_ALTITUDE_SMOOTHING_VALUE: Int = 13
|
||||||
const val DEFAULT_THRESHOLD_LOCATION_ACCURACY: Int = 30 // 30 meters
|
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 = 60000000000L // one minute in nanoseconds
|
||||||
const val DEFAULT_THRESHOLD_DISTANCE: Float = 15f // 15 meters
|
const val DEFAULT_THRESHOLD_DISTANCE: Float = 15f // 15 meters
|
||||||
|
|
|
@ -22,10 +22,7 @@ import android.Manifest
|
||||||
import android.content.*
|
import android.content.*
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.location.Location
|
import android.location.Location
|
||||||
import android.os.Build
|
import android.os.*
|
||||||
import android.os.Bundle
|
|
||||||
import android.os.Handler
|
|
||||||
import android.os.IBinder
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
@ -55,7 +52,7 @@ class MapFragment : Fragment(), YesNoDialog.YesNoDialogListener, MapOverlayHelpe
|
||||||
|
|
||||||
/* Main class variables */
|
/* Main class variables */
|
||||||
private var bound: Boolean = false
|
private var bound: Boolean = false
|
||||||
private val handler: Handler = Handler()
|
private val handler: Handler = Handler(Looper.getMainLooper())
|
||||||
private var trackingState: Int = Keys.STATE_TRACKING_NOT
|
private var trackingState: Int = Keys.STATE_TRACKING_NOT
|
||||||
private var gpsProviderActive: Boolean = false
|
private var gpsProviderActive: Boolean = false
|
||||||
private var networkProviderActive: Boolean = false
|
private var networkProviderActive: Boolean = false
|
||||||
|
|
|
@ -116,15 +116,15 @@ class SettingsFragment : PreferenceFragmentCompat(), YesNoDialog.YesNoDialogList
|
||||||
preferenceRecordingAccuracy.setDefaultValue(false)
|
preferenceRecordingAccuracy.setDefaultValue(false)
|
||||||
|
|
||||||
// set up "Altitude Smoothing" preference
|
// set up "Altitude Smoothing" preference
|
||||||
val preferenceAltitudeSmoothingValue: SeekBarPreference = SeekBarPreference(activity as Context)
|
// val preferenceAltitudeSmoothingValue: SeekBarPreference = SeekBarPreference(activity as Context)
|
||||||
preferenceAltitudeSmoothingValue.title = getString(R.string.pref_altitude_smoothing_value_title)
|
// preferenceAltitudeSmoothingValue.title = getString(R.string.pref_altitude_smoothing_value_title)
|
||||||
preferenceAltitudeSmoothingValue.setIcon(R.drawable.ic_bar_chart_24)
|
// preferenceAltitudeSmoothingValue.setIcon(R.drawable.ic_bar_chart_24)
|
||||||
preferenceAltitudeSmoothingValue.key = Keys.PREF_ALTITUDE_SMOOTHING_VALUE
|
// preferenceAltitudeSmoothingValue.key = Keys.PREF_ALTITUDE_SMOOTHING_VALUE
|
||||||
preferenceAltitudeSmoothingValue.summary = getString(R.string.pref_altitude_smoothing_value_summary)
|
// preferenceAltitudeSmoothingValue.summary = getString(R.string.pref_altitude_smoothing_value_summary)
|
||||||
preferenceAltitudeSmoothingValue.showSeekBarValue = true
|
// preferenceAltitudeSmoothingValue.showSeekBarValue = true
|
||||||
preferenceAltitudeSmoothingValue.min = Keys.MIN_NUMBER_OF_WAYPOINTS_FOR_ELEVATION_CALCULATION
|
// preferenceAltitudeSmoothingValue.min = Keys.MIN_NUMBER_OF_WAYPOINTS_FOR_ELEVATION_CALCULATION
|
||||||
preferenceAltitudeSmoothingValue.max = Keys.MAX_NUMBER_OF_WAYPOINTS_FOR_ELEVATION_CALCULATION
|
// preferenceAltitudeSmoothingValue.max = Keys.MAX_NUMBER_OF_WAYPOINTS_FOR_ELEVATION_CALCULATION
|
||||||
preferenceAltitudeSmoothingValue.setDefaultValue(Keys.DEFAULT_ALTITUDE_SMOOTHING_VALUE)
|
// preferenceAltitudeSmoothingValue.setDefaultValue(Keys.DEFAULT_ALTITUDE_SMOOTHING_VALUE)
|
||||||
|
|
||||||
|
|
||||||
// set up "Reset" preference
|
// set up "Reset" preference
|
||||||
|
@ -135,7 +135,7 @@ class SettingsFragment : PreferenceFragmentCompat(), YesNoDialog.YesNoDialogList
|
||||||
preferenceResetAdvanced.setOnPreferenceClickListener{
|
preferenceResetAdvanced.setOnPreferenceClickListener{
|
||||||
// reset "Recording Accuracy" preference
|
// reset "Recording Accuracy" preference
|
||||||
preferenceRecordingAccuracy.isChecked = false
|
preferenceRecordingAccuracy.isChecked = false
|
||||||
preferenceAltitudeSmoothingValue.value = Keys.DEFAULT_ALTITUDE_SMOOTHING_VALUE
|
// preferenceAltitudeSmoothingValue.value = Keys.DEFAULT_ALTITUDE_SMOOTHING_VALUE
|
||||||
return@setOnPreferenceClickListener true
|
return@setOnPreferenceClickListener true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,7 +181,7 @@ class SettingsFragment : PreferenceFragmentCompat(), YesNoDialog.YesNoDialogList
|
||||||
val preferenceCategoryAdvanced: PreferenceCategory = PreferenceCategory(activity as Context)
|
val preferenceCategoryAdvanced: PreferenceCategory = PreferenceCategory(activity as Context)
|
||||||
preferenceCategoryAdvanced.title = getString(R.string.pref_advanced_title)
|
preferenceCategoryAdvanced.title = getString(R.string.pref_advanced_title)
|
||||||
preferenceCategoryAdvanced.contains(preferenceRecordingAccuracy)
|
preferenceCategoryAdvanced.contains(preferenceRecordingAccuracy)
|
||||||
preferenceCategoryAdvanced.contains(preferenceAltitudeSmoothingValue)
|
// preferenceCategoryAdvanced.contains(preferenceAltitudeSmoothingValue)
|
||||||
preferenceCategoryAdvanced.contains(preferenceResetAdvanced)
|
preferenceCategoryAdvanced.contains(preferenceResetAdvanced)
|
||||||
|
|
||||||
val preferenceCategoryAbout: PreferenceCategory = PreferenceCategory(context)
|
val preferenceCategoryAbout: PreferenceCategory = PreferenceCategory(context)
|
||||||
|
@ -198,7 +198,7 @@ class SettingsFragment : PreferenceFragmentCompat(), YesNoDialog.YesNoDialogList
|
||||||
screen.addPreference(preferenceDeleteNonStarred)
|
screen.addPreference(preferenceDeleteNonStarred)
|
||||||
screen.addPreference(preferenceCategoryAdvanced)
|
screen.addPreference(preferenceCategoryAdvanced)
|
||||||
screen.addPreference(preferenceRecordingAccuracy)
|
screen.addPreference(preferenceRecordingAccuracy)
|
||||||
screen.addPreference(preferenceAltitudeSmoothingValue)
|
// screen.addPreference(preferenceAltitudeSmoothingValue)
|
||||||
screen.addPreference(preferenceResetAdvanced)
|
screen.addPreference(preferenceResetAdvanced)
|
||||||
screen.addPreference(preferenceCategoryAbout)
|
screen.addPreference(preferenceCategoryAbout)
|
||||||
screen.addPreference(preferenceAppVersion)
|
screen.addPreference(preferenceAppVersion)
|
||||||
|
|
|
@ -32,10 +32,7 @@ import android.hardware.SensorManager
|
||||||
import android.location.Location
|
import android.location.Location
|
||||||
import android.location.LocationListener
|
import android.location.LocationListener
|
||||||
import android.location.LocationManager
|
import android.location.LocationManager
|
||||||
import android.os.Binder
|
import android.os.*
|
||||||
import android.os.Bundle
|
|
||||||
import android.os.Handler
|
|
||||||
import android.os.IBinder
|
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.Dispatchers.IO
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
|
@ -69,7 +66,7 @@ class TrackerService: Service(), SensorEventListener {
|
||||||
var networkLocationListenerRegistered: Boolean = false
|
var networkLocationListenerRegistered: Boolean = false
|
||||||
var bound: Boolean = false
|
var bound: Boolean = false
|
||||||
private val binder = LocalBinder()
|
private val binder = LocalBinder()
|
||||||
private val handler: Handler = Handler()
|
private val handler: Handler = Handler(Looper.getMainLooper())
|
||||||
private var altitudeValues: SimpleMovingAverageQueue = SimpleMovingAverageQueue(Keys.DEFAULT_ALTITUDE_SMOOTHING_VALUE)
|
private var altitudeValues: SimpleMovingAverageQueue = SimpleMovingAverageQueue(Keys.DEFAULT_ALTITUDE_SMOOTHING_VALUE)
|
||||||
private lateinit var locationManager: LocationManager
|
private lateinit var locationManager: LocationManager
|
||||||
private lateinit var sensorManager: SensorManager
|
private lateinit var sensorManager: SensorManager
|
||||||
|
@ -97,7 +94,7 @@ class TrackerService: Service(), SensorEventListener {
|
||||||
trackingState = PreferencesHelper.loadTrackingState()
|
trackingState = PreferencesHelper.loadTrackingState()
|
||||||
currentBestLocation = LocationHelper.getLastKnownLocation(this)
|
currentBestLocation = LocationHelper.getLastKnownLocation(this)
|
||||||
track = FileHelper.readTrack(this, FileHelper.getTempFileUri(this))
|
track = FileHelper.readTrack(this, FileHelper.getTempFileUri(this))
|
||||||
altitudeValues.capacity = PreferencesHelper.loadAltitudeSmoothingValue()
|
// altitudeValues.capacity = PreferencesHelper.loadAltitudeSmoothingValue()
|
||||||
PreferencesHelper.registerPreferenceChangeListener(sharedPreferenceChangeListener)
|
PreferencesHelper.registerPreferenceChangeListener(sharedPreferenceChangeListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -577,16 +574,16 @@ class TrackerService: Service(), SensorEventListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO remove
|
// // TODO remove
|
||||||
val testAltitudes: Array<Double> = arrayOf(352.4349365234375, 358.883544921875, 358.6827392578125, 357.31396484375, 354.27459716796875, 354.573486328125, 354.388916015625, 354.6697998046875, 356.534912109375, 355.2772216796875, 356.21246337890625, 352.3499755859375, 350.37646484375, 351.2098388671875, 350.5213623046875, 350.5145263671875, 350.1728515625, 350.9075927734375, 351.5965576171875, 349.55767822265625, 351.548583984375, 357.1195068359375, 362.18634033203125, 366.3153076171875, 366.2218017578125, 362.1046142578125, 357.48291015625, 356.78570556640625, 353.7734375, 352.53936767578125, 351.8125, 353.1099853515625, 354.93035888671875, 355.4337158203125, 354.83270263671875, 352.9859619140625, 352.3006591796875, 351.63470458984375, 350.2501220703125, 351.75726318359375, 350.87664794921875, 350.4185791015625, 350.51568603515625, 349.5537109375, 345.2874755859375, 345.57196044921875, 349.99658203125, 353.3822021484375, 355.19061279296875, 359.1099853515625, 361.74365234375, 363.313232421875, 362.026611328125, 363.20703125, 363.2508544921875, 362.5870361328125, 362.521240234375)
|
// val testAltitudes: Array<Double> = arrayOf(352.4349365234375, 358.883544921875, 358.6827392578125, 357.31396484375, 354.27459716796875, 354.573486328125, 354.388916015625, 354.6697998046875, 356.534912109375, 355.2772216796875, 356.21246337890625, 352.3499755859375, 350.37646484375, 351.2098388671875, 350.5213623046875, 350.5145263671875, 350.1728515625, 350.9075927734375, 351.5965576171875, 349.55767822265625, 351.548583984375, 357.1195068359375, 362.18634033203125, 366.3153076171875, 366.2218017578125, 362.1046142578125, 357.48291015625, 356.78570556640625, 353.7734375, 352.53936767578125, 351.8125, 353.1099853515625, 354.93035888671875, 355.4337158203125, 354.83270263671875, 352.9859619140625, 352.3006591796875, 351.63470458984375, 350.2501220703125, 351.75726318359375, 350.87664794921875, 350.4185791015625, 350.51568603515625, 349.5537109375, 345.2874755859375, 345.57196044921875, 349.99658203125, 353.3822021484375, 355.19061279296875, 359.1099853515625, 361.74365234375, 363.313232421875, 362.026611328125, 363.20703125, 363.2508544921875, 362.5870361328125, 362.521240234375)
|
||||||
var testCounter: Int = 0
|
// var testCounter: Int = 0
|
||||||
fun getTestAltitude(): Double {
|
// fun getTestAltitude(): Double {
|
||||||
if (testCounter >= testAltitudes.size) testCounter = 0
|
// if (testCounter >= testAltitudes.size) testCounter = 0
|
||||||
val testAltitude: Double = testAltitudes[testCounter]
|
// val testAltitude: Double = testAltitudes[testCounter]
|
||||||
testCounter ++
|
// testCounter ++
|
||||||
return testAltitude
|
// return testAltitude
|
||||||
}
|
// }
|
||||||
// TODO remove
|
// // TODO remove
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,7 +84,7 @@ class TracklistFragment : Fragment(), TracklistAdapter.TracklistAdapterListener,
|
||||||
val swipeHandler = object : UiHelper.SwipeToDeleteCallback(activity as Context) {
|
val swipeHandler = object : UiHelper.SwipeToDeleteCallback(activity as Context) {
|
||||||
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
|
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
|
||||||
// ask user
|
// ask user
|
||||||
val adapterPosition: Int = viewHolder.adapterPosition
|
val adapterPosition: Int = viewHolder.adapterPosition // first position in list is reserved for statistics
|
||||||
val dialogMessage: String = "${getString(R.string.dialog_yes_no_message_delete_recording)}\n\n- ${tracklistAdapter.getTrackName(adapterPosition)}"
|
val dialogMessage: String = "${getString(R.string.dialog_yes_no_message_delete_recording)}\n\n- ${tracklistAdapter.getTrackName(adapterPosition)}"
|
||||||
YesNoDialog(this@TracklistFragment as YesNoDialog.YesNoDialogListener).show(context = activity as Context, type = Keys.DIALOG_DELETE_TRACK, messageString = dialogMessage, yesButton = R.string.dialog_yes_no_positive_button_delete_recording, payload = adapterPosition)
|
YesNoDialog(this@TracklistFragment as YesNoDialog.YesNoDialogListener).show(context = activity as Context, type = Keys.DIALOG_DELETE_TRACK, messageString = dialogMessage, yesButton = R.string.dialog_yes_no_positive_button_delete_recording, payload = adapterPosition)
|
||||||
}
|
}
|
||||||
|
@ -93,7 +93,7 @@ class TracklistFragment : Fragment(), TracklistAdapter.TracklistAdapterListener,
|
||||||
itemTouchHelper.attachToRecyclerView(rootView.findViewById(R.id.track_element_list))
|
itemTouchHelper.attachToRecyclerView(rootView.findViewById(R.id.track_element_list))
|
||||||
|
|
||||||
// toggle onboarding layout
|
// toggle onboarding layout
|
||||||
toggleOnboardingLayout(tracklistAdapter.itemCount)
|
toggleOnboardingLayout()
|
||||||
|
|
||||||
return rootView
|
return rootView
|
||||||
}
|
}
|
||||||
|
@ -118,7 +118,7 @@ class TracklistFragment : Fragment(), TracklistAdapter.TracklistAdapterListener,
|
||||||
when (dialogResult) {
|
when (dialogResult) {
|
||||||
// user tapped remove track
|
// user tapped remove track
|
||||||
true -> {
|
true -> {
|
||||||
toggleOnboardingLayout(tracklistAdapter.itemCount -1)
|
toggleOnboardingLayout()
|
||||||
tracklistAdapter.removeTrackAtPosition(activity as Context, payload)
|
tracklistAdapter.removeTrackAtPosition(activity as Context, payload)
|
||||||
}
|
}
|
||||||
// user tapped cancel
|
// user tapped cancel
|
||||||
|
@ -132,8 +132,8 @@ class TracklistFragment : Fragment(), TracklistAdapter.TracklistAdapterListener,
|
||||||
|
|
||||||
|
|
||||||
// toggle onboarding layout
|
// toggle onboarding layout
|
||||||
private fun toggleOnboardingLayout(trackCount: Int) {
|
private fun toggleOnboardingLayout() {
|
||||||
when (trackCount == 0) {
|
when (tracklistAdapter.isEmpty()) {
|
||||||
true -> {
|
true -> {
|
||||||
// show onboarding layout
|
// show onboarding layout
|
||||||
tracklistOnboarding.visibility = View.VISIBLE
|
tracklistOnboarding.visibility = View.VISIBLE
|
||||||
|
@ -166,7 +166,7 @@ class TracklistFragment : Fragment(), TracklistAdapter.TracklistAdapterListener,
|
||||||
if (deleteTrackId != -1L) {
|
if (deleteTrackId != -1L) {
|
||||||
CoroutineScope(Main). launch {
|
CoroutineScope(Main). launch {
|
||||||
tracklistAdapter.removeTrackById(this@TracklistFragment.activity as Context, deleteTrackId)
|
tracklistAdapter.removeTrackById(this@TracklistFragment.activity as Context, deleteTrackId)
|
||||||
toggleOnboardingLayout(tracklistAdapter.itemCount - 1)
|
toggleOnboardingLayout()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,7 +84,7 @@ class YesNoDialog (private var yesNoDialogListener: YesNoDialogListener) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle outside-click as "no"
|
// handle outside-click as "no"
|
||||||
builder.setOnCancelListener{
|
builder.setOnCancelListener {
|
||||||
yesNoDialogListener.onYesNoDialog(type, false, payload, payloadString)
|
yesNoDialogListener.onYesNoDialog(type, false, payload, payloadString)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -182,9 +182,9 @@ object FileHelper {
|
||||||
val tracklist: Tracklist = readTracklist(context)
|
val tracklist: Tracklist = readTracklist(context)
|
||||||
tracklist.tracklistElements.add(track.toTracklistElement(context))
|
tracklist.tracklistElements.add(track.toTracklistElement(context))
|
||||||
tracklist.totalDistanceAll += track.length
|
tracklist.totalDistanceAll += track.length
|
||||||
tracklist.totalDurationAll += track.duration
|
// tracklist.totalDurationAll += track.duration // note: TracklistElement does not contain duration
|
||||||
tracklist.totalRecordingPausedAll += track.recordingPaused
|
// tracklist.totalRecordingPausedAll += track.recordingPaused // note: TracklistElement does not contain recordingPaused
|
||||||
tracklist.totalStepCountAll += track.stepCount
|
// tracklist.totalStepCountAll += track.stepCount // note: TracklistElement does not contain stepCount
|
||||||
cont.resume(saveTracklist(context, tracklist, modificationDate))
|
cont.resume(saveTracklist(context, tracklist, modificationDate))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -340,6 +340,8 @@ object FileHelper {
|
||||||
// delete track files
|
// delete track files
|
||||||
tracklistElement.trackUriString.toUri().toFile().delete()
|
tracklistElement.trackUriString.toUri().toFile().delete()
|
||||||
tracklistElement.gpxUriString.toUri().toFile().delete()
|
tracklistElement.gpxUriString.toUri().toFile().delete()
|
||||||
|
// subtract track length from total distance
|
||||||
|
tracklist.totalDistanceAll -= tracklistElement.length
|
||||||
}
|
}
|
||||||
tracklist.tracklistElements.removeAll{ tracklistElements.contains(it) }
|
tracklist.tracklistElements.removeAll{ tracklistElements.contains(it) }
|
||||||
saveTracklist(context, tracklist, GregorianCalendar.getInstance().time)
|
saveTracklist(context, tracklist, GregorianCalendar.getInstance().time)
|
||||||
|
@ -353,6 +355,8 @@ object FileHelper {
|
||||||
// delete track files
|
// delete track files
|
||||||
tracklistElement.trackUriString.toUri().toFile().delete()
|
tracklistElement.trackUriString.toUri().toFile().delete()
|
||||||
tracklistElement.gpxUriString.toUri().toFile().delete()
|
tracklistElement.gpxUriString.toUri().toFile().delete()
|
||||||
|
// subtract track length from total distance
|
||||||
|
tracklist.totalDistanceAll -= tracklistElement.length
|
||||||
// remove track element from list
|
// remove track element from list
|
||||||
tracklist.tracklistElements.removeIf { TrackHelper.getTrackId(it) == TrackHelper.getTrackId(tracklistElement) }
|
tracklist.tracklistElements.removeIf { TrackHelper.getTrackId(it) == TrackHelper.getTrackId(tracklistElement) }
|
||||||
saveTracklist(context, tracklist, GregorianCalendar.getInstance().time)
|
saveTracklist(context, tracklist, GregorianCalendar.getInstance().time)
|
||||||
|
|
|
@ -87,19 +87,19 @@ object PreferencesHelper {
|
||||||
return sharedPreferences.getBoolean(Keys.PREF_GPS_ONLY, false)
|
return sharedPreferences.getBoolean(Keys.PREF_GPS_ONLY, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loads accuracy threshold used to determine if location is good enough */
|
// /* Loads accuracy threshold used to determine if location is good enough */
|
||||||
fun loadAccuracyThreshold(): Int {
|
// fun loadAccuracyThreshold(): Int {
|
||||||
// load tracking state
|
// // load tracking state
|
||||||
return sharedPreferences.getInt(Keys.PREF_LOCATION_ACCURACY_THRESHOLD, Keys.DEFAULT_THRESHOLD_LOCATION_ACCURACY)
|
// return sharedPreferences.getInt(Keys.PREF_LOCATION_ACCURACY_THRESHOLD, Keys.DEFAULT_THRESHOLD_LOCATION_ACCURACY)
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Loads state of recording accuracy */
|
// /* Loads state of recording accuracy */
|
||||||
fun loadRecordingAccuracyHigh(): Boolean {
|
// fun loadRecordingAccuracyHigh(): Boolean {
|
||||||
// load current setting
|
// // load current setting
|
||||||
return sharedPreferences.getBoolean(Keys.PREF_RECORDING_ACCURACY_HIGH, false)
|
// return sharedPreferences.getBoolean(Keys.PREF_RECORDING_ACCURACY_HIGH, false)
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
/* Loads current accuracy multiplier */
|
/* Loads current accuracy multiplier */
|
||||||
|
@ -111,11 +111,11 @@ object PreferencesHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Load altitude smoothing value */
|
// /* Load altitude smoothing value */
|
||||||
fun loadAltitudeSmoothingValue(): Int {
|
// fun loadAltitudeSmoothingValue(): Int {
|
||||||
// load current setting
|
// // load current setting
|
||||||
return sharedPreferences.getInt(Keys.PREF_ALTITUDE_SMOOTHING_VALUE, Keys.DEFAULT_ALTITUDE_SMOOTHING_VALUE)
|
// return sharedPreferences.getInt(Keys.PREF_ALTITUDE_SMOOTHING_VALUE, Keys.DEFAULT_ALTITUDE_SMOOTHING_VALUE)
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
/* Loads the state of a map */
|
/* Loads the state of a map */
|
||||||
|
|
|
@ -44,13 +44,11 @@ object TrackHelper {
|
||||||
|
|
||||||
|
|
||||||
/* Returns unique ID for Track - currently the start date */
|
/* Returns unique ID for Track - currently the start date */
|
||||||
fun getTrackId(track: Track): Long =
|
fun getTrackId(track: Track): Long = track.recordingStart.time
|
||||||
track.recordingStart.time
|
|
||||||
|
|
||||||
|
|
||||||
/* Returns unique ID for TracklistElement - currently the start date */
|
/* Returns unique ID for TracklistElement - currently the start date */
|
||||||
fun getTrackId(tracklistElement: TracklistElement): Long =
|
fun getTrackId(tracklistElement: TracklistElement): Long = tracklistElement.date.time
|
||||||
tracklistElement.date.time
|
|
||||||
|
|
||||||
|
|
||||||
/* Adds given locatiom as waypoint to track */
|
/* Adds given locatiom as waypoint to track */
|
||||||
|
@ -258,20 +256,20 @@ object TrackHelper {
|
||||||
fun calculateAndSaveTrackTotals(context: Context, tracklist: Tracklist) {
|
fun calculateAndSaveTrackTotals(context: Context, tracklist: Tracklist) {
|
||||||
CoroutineScope(IO).launch {
|
CoroutineScope(IO).launch {
|
||||||
var totalDistanceAll: Float = 0f
|
var totalDistanceAll: Float = 0f
|
||||||
var totalDurationAll: Long = 0L
|
// var totalDurationAll: Long = 0L
|
||||||
var totalRecordingPausedAll: Long = 0L
|
// var totalRecordingPausedAll: Long = 0L
|
||||||
var totalStepCountAll: Float = 0f
|
// var totalStepCountAll: Float = 0f
|
||||||
tracklist.tracklistElements.forEach { tracklistElement ->
|
tracklist.tracklistElements.forEach { tracklistElement ->
|
||||||
val track: Track = FileHelper.readTrack(context, tracklistElement.trackUriString.toUri())
|
val track: Track = FileHelper.readTrack(context, tracklistElement.trackUriString.toUri())
|
||||||
totalDistanceAll += track.length
|
totalDistanceAll += track.length
|
||||||
totalDurationAll += track.duration
|
// totalDurationAll += track.duration
|
||||||
totalRecordingPausedAll += track.recordingPaused
|
// totalRecordingPausedAll += track.recordingPaused
|
||||||
totalStepCountAll += track.stepCount
|
// totalStepCountAll += track.stepCount
|
||||||
}
|
}
|
||||||
tracklist.totalDistanceAll = totalDistanceAll
|
tracklist.totalDistanceAll = totalDistanceAll
|
||||||
tracklist.totalDurationAll = totalDurationAll
|
// tracklist.totalDurationAll = totalDurationAll
|
||||||
tracklist.totalRecordingPausedAll = totalRecordingPausedAll
|
// tracklist.totalRecordingPausedAll = totalRecordingPausedAll
|
||||||
tracklist.totalStepCountAll = totalStepCountAll
|
// tracklist.totalStepCountAll = totalStepCountAll
|
||||||
FileHelper.saveTracklistSuspended(context, tracklist, GregorianCalendar.getInstance().time)
|
FileHelper.saveTracklistSuspended(context, tracklist, GregorianCalendar.getInstance().time)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ import androidx.core.content.ContextCompat
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import org.y20k.trackbook.R
|
import org.y20k.trackbook.R
|
||||||
|
import org.y20k.trackbook.tracklist.TracklistAdapter
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -101,6 +102,12 @@ object UiHelper {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onChildDraw(c: Canvas, recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, dX: Float, dY: Float, actionState: Int, isCurrentlyActive: Boolean) {
|
override fun onChildDraw(c: Canvas, recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, dX: Float, dY: Float, actionState: Int, isCurrentlyActive: Boolean) {
|
||||||
val itemView = viewHolder.itemView
|
val itemView = viewHolder.itemView
|
||||||
val itemHeight = itemView.bottom - itemView.top
|
val itemHeight = itemView.bottom - itemView.top
|
||||||
|
|
|
@ -32,6 +32,7 @@ import androidx.recyclerview.widget.RecyclerView
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.Dispatchers.IO
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
import kotlinx.coroutines.Dispatchers.Main
|
import kotlinx.coroutines.Dispatchers.Main
|
||||||
|
import org.y20k.trackbook.Keys
|
||||||
import org.y20k.trackbook.R
|
import org.y20k.trackbook.R
|
||||||
import org.y20k.trackbook.core.Tracklist
|
import org.y20k.trackbook.core.Tracklist
|
||||||
import org.y20k.trackbook.core.TracklistElement
|
import org.y20k.trackbook.core.TracklistElement
|
||||||
|
@ -78,49 +79,89 @@ class TracklistAdapter(private val fragment: Fragment) : RecyclerView.Adapter<Re
|
||||||
|
|
||||||
/* Overrides onCreateViewHolder from RecyclerView.Adapter */
|
/* Overrides onCreateViewHolder from RecyclerView.Adapter */
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||||
val v = LayoutInflater.from(parent.context).inflate(R.layout.track_element, parent, false)
|
|
||||||
return TrackElementViewHolder(v)
|
when (viewType) {
|
||||||
|
Keys.VIEW_TYPE_STATISTICS -> {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Overrides getItemViewType */
|
||||||
|
override fun getItemViewType(position: Int): Int {
|
||||||
|
if (position == 0) {
|
||||||
|
return Keys.VIEW_TYPE_STATISTICS
|
||||||
|
} else {
|
||||||
|
return Keys.VIEW_TYPE_TRACK
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Overrides getItemCount from RecyclerView.Adapter */
|
/* Overrides getItemCount from RecyclerView.Adapter */
|
||||||
override fun getItemCount(): Int {
|
override fun getItemCount(): Int {
|
||||||
return tracklist.tracklistElements.size
|
// +1 ==> the total statistics element
|
||||||
|
return tracklist.tracklistElements.size + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Overrides onBindViewHolder from RecyclerView.Adapter */
|
/* Overrides onBindViewHolder from RecyclerView.Adapter */
|
||||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||||
val trackElementViewHolder: TrackElementViewHolder = holder as TrackElementViewHolder
|
|
||||||
trackElementViewHolder.trackNameView.text = tracklist.tracklistElements[position].name
|
when (holder) {
|
||||||
trackElementViewHolder.trackDataView.text = createTrackDataString(position)
|
|
||||||
when (tracklist.tracklistElements[position].starred) {
|
// CASE STATISTICS ELEMENT
|
||||||
true -> trackElementViewHolder.starButton.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_star_filled_24dp))
|
is ElementStatisticsViewHolder -> {
|
||||||
false -> trackElementViewHolder.starButton.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_star_outline_24dp))
|
val elementStatisticsViewHolder: ElementStatisticsViewHolder = holder as ElementStatisticsViewHolder
|
||||||
}
|
elementStatisticsViewHolder.totalDistanceView.text = LengthUnitHelper.convertDistanceToString(tracklist.totalDistanceAll, useImperial)
|
||||||
trackElementViewHolder.trackElement.setOnClickListener {
|
}
|
||||||
tracklistListener.onTrackElementTapped(tracklist.tracklistElements[position])
|
|
||||||
}
|
// CASE TRACK ELEMENT
|
||||||
trackElementViewHolder.starButton.setOnClickListener {
|
is ElementTrackViewHolder -> {
|
||||||
toggleStarred(it, position)
|
val positionInTracklist: Int = position -1
|
||||||
|
val elementTrackViewHolder: ElementTrackViewHolder = holder as ElementTrackViewHolder
|
||||||
|
elementTrackViewHolder.trackNameView.text = tracklist.tracklistElements[positionInTracklist].name
|
||||||
|
elementTrackViewHolder.trackDataView.text = createTrackDataString(positionInTracklist)
|
||||||
|
when (tracklist.tracklistElements[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.tracklistElements[positionInTracklist])
|
||||||
|
}
|
||||||
|
elementTrackViewHolder.starButton.setOnClickListener {
|
||||||
|
toggleStarred(it, positionInTracklist)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Get track name for given position */
|
/* Get track name for given position */
|
||||||
fun getTrackName(position: Int): String {
|
fun getTrackName(positionInRecyclerView: Int): String {
|
||||||
return tracklist.tracklistElements[position].name
|
// first position is always the statistics element
|
||||||
|
return tracklist.tracklistElements[positionInRecyclerView - 1].name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Removes track and track files for given position - used by TracklistFragment */
|
/* Removes track and track files for given position - used by TracklistFragment */
|
||||||
fun removeTrackAtPosition(context: Context, position: Int) {
|
fun removeTrackAtPosition(context: Context, position: Int) {
|
||||||
CoroutineScope(IO).launch {
|
CoroutineScope(IO).launch {
|
||||||
val deferred: Deferred<Tracklist> = async { FileHelper.deleteTrackSuspended(context, position, tracklist) }
|
val positionInTracklist = position - 1
|
||||||
|
val deferred: Deferred<Tracklist> = async { FileHelper.deleteTrackSuspended(context, positionInTracklist, tracklist) }
|
||||||
// wait for result and store in tracklist
|
// wait for result and store in tracklist
|
||||||
withContext(Main) {
|
withContext(Main) {
|
||||||
tracklist = deferred.await()
|
tracklist = deferred.await()
|
||||||
notifyItemRemoved(position) }
|
notifyItemRemoved(position)
|
||||||
|
notifyItemChanged(0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,16 +171,25 @@ class TracklistAdapter(private val fragment: Fragment) : RecyclerView.Adapter<Re
|
||||||
CoroutineScope(IO).launch {
|
CoroutineScope(IO).launch {
|
||||||
// reload tracklist //todo check if necessary
|
// reload tracklist //todo check if necessary
|
||||||
// tracklist = FileHelper.readTracklist(context)
|
// tracklist = FileHelper.readTracklist(context)
|
||||||
val position: Int = findPosition(trackId)
|
val positionInTracklist: Int = findPosition(trackId)
|
||||||
val deferred: Deferred<Tracklist> = async { FileHelper.deleteTrackSuspended(context, position, tracklist) }
|
val deferred: Deferred<Tracklist> = async { FileHelper.deleteTrackSuspended(context, positionInTracklist, tracklist) }
|
||||||
// wait for result and store in tracklist
|
// wait for result and store in tracklist
|
||||||
withContext(Main) {
|
withContext(Main) {
|
||||||
tracklist = deferred.await()
|
tracklist = deferred.await()
|
||||||
notifyItemRemoved(position) }
|
val positionInRecyclerView: Int = positionInTracklist + 1 // position 0 is the statistics element
|
||||||
|
notifyItemRemoved(positionInRecyclerView)
|
||||||
|
notifyItemChanged(0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Returns if the adapter is empty */
|
||||||
|
fun isEmpty(): Boolean {
|
||||||
|
return tracklist.tracklistElements.size == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Finds current position of track element in adapter list */
|
/* Finds current position of track element in adapter list */
|
||||||
private fun findPosition(trackId: Long): Int {
|
private fun findPosition(trackId: Long): Int {
|
||||||
tracklist.tracklistElements.forEachIndexed {index, tracklistElement ->
|
tracklist.tracklistElements.forEachIndexed {index, tracklistElement ->
|
||||||
|
@ -215,11 +265,23 @@ class TracklistAdapter(private val fragment: Fragment) : RecyclerView.Adapter<Re
|
||||||
/*
|
/*
|
||||||
* Inner class: ViewHolder for a track element
|
* Inner class: ViewHolder for a track element
|
||||||
*/
|
*/
|
||||||
private inner class TrackElementViewHolder (trackElementLayout: View): RecyclerView.ViewHolder(trackElementLayout) {
|
inner class ElementTrackViewHolder (elementTrackLayout: View): RecyclerView.ViewHolder(elementTrackLayout) {
|
||||||
val trackElement: ConstraintLayout = trackElementLayout.findViewById(R.id.track_element)
|
val trackElement: ConstraintLayout = elementTrackLayout.findViewById(R.id.track_element)
|
||||||
val trackNameView: TextView = trackElementLayout.findViewById(R.id.track_name)
|
val trackNameView: TextView = elementTrackLayout.findViewById(R.id.track_name)
|
||||||
val trackDataView: TextView = trackElementLayout.findViewById(R.id.track_data)
|
val trackDataView: TextView = elementTrackLayout.findViewById(R.id.track_data)
|
||||||
val starButton: ImageButton = trackElementLayout.findViewById(R.id.star_button)
|
val starButton: ImageButton = elementTrackLayout.findViewById(R.id.star_button)
|
||||||
|
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* End of inner class
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Inner class: ViewHolder for a statistics element
|
||||||
|
*/
|
||||||
|
inner class ElementStatisticsViewHolder (elementStatisticsLayout: View): RecyclerView.ViewHolder(elementStatisticsLayout) {
|
||||||
|
val totalDistanceView: TextView = elementStatisticsLayout.findViewById(R.id.total_distance_data)
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* End of inner class
|
* End of inner class
|
||||||
|
|
33
app/src/main/res/layout/element_statistics.xml
Normal file
33
app/src/main/res/layout/element_statistics.xml
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<?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">
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/total_distance_p"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="24dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginEnd="24dp"
|
||||||
|
android:text="@string/track_list_p_element_statistics"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Body2"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/total_distance_data"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline4"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="@+id/total_distance_p"
|
||||||
|
app:layout_constraintStart_toStartOf="@+id/total_distance_p"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/total_distance_p"
|
||||||
|
tools:text="@string/sample_text_default_total_distance" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -72,6 +72,8 @@
|
||||||
<!-- Track Tab Onboarding -->
|
<!-- Track Tab Onboarding -->
|
||||||
<string name="track_list_onboarding_h1_part_1">Your recorded tracks</string>
|
<string name="track_list_onboarding_h1_part_1">Your recorded tracks</string>
|
||||||
<string name="track_list_onboarding_h1_part_2">… will show up here.</string>
|
<string name="track_list_onboarding_h1_part_2">… will show up here.</string>
|
||||||
|
<!-- Track List -->
|
||||||
|
<string name="track_list_p_element_statistics">Total Distance Recorded</string>
|
||||||
<!-- Settings -->
|
<!-- Settings -->
|
||||||
<string name="pref_about_title">About</string>
|
<string name="pref_about_title">About</string>
|
||||||
<string name="pref_app_version_summary">Version</string>
|
<string name="pref_app_version_summary">Version</string>
|
||||||
|
@ -124,4 +126,5 @@
|
||||||
<string name="sample_text_track_data" translatable="false">23.0 km • 5 hrs 23 min 42 sec</string>
|
<string name="sample_text_track_data" translatable="false">23.0 km • 5 hrs 23 min 42 sec</string>
|
||||||
<string name="sample_text_track_name" translatable="false">July 20, 1969</string>
|
<string name="sample_text_track_name" translatable="false">July 20, 1969</string>
|
||||||
<string name="sample_text_default_data" translatable="false">track data missing</string>
|
<string name="sample_text_default_data" translatable="false">track data missing</string>
|
||||||
|
<string name="sample_text_default_total_distance" translatable="false">6357.23 km</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
ext {
|
ext {
|
||||||
kotlin_version = '1.5.20'
|
kotlin_version = '1.5.30'
|
||||||
navigation_version = '2.3.3'
|
navigation_version = '2.3.3'
|
||||||
}
|
}
|
||||||
repositories {
|
repositories {
|
||||||
|
@ -10,7 +10,7 @@ buildscript {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:4.2.2'
|
classpath 'com.android.tools.build:gradle:7.0.2'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$navigation_version"
|
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$navigation_version"
|
||||||
|
|
||||||
|
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,5 +1,5 @@
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|
Loading…
Reference in a new issue