diff --git a/app/build.gradle b/app/build.gradle index 451447c..c7b5c27 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -58,18 +58,18 @@ dependencies { // AndroidX def navigationVersion = "2.3.5" - implementation "androidx.activity:activity-ktx:1.2.3" - implementation 'androidx.appcompat:appcompat:1.3.0' - implementation 'androidx.constraintlayout:constraintlayout:2.0.4' - implementation 'androidx.core:core-ktx:1.5.0' + implementation "androidx.activity:activity-ktx:1.3.1" + implementation 'androidx.appcompat:appcompat:1.3.1' + implementation 'androidx.constraintlayout:constraintlayout:2.1.0' + implementation 'androidx.core:core-ktx:1.6.0' implementation "androidx.navigation:navigation-fragment-ktx:$navigationVersion" implementation "androidx.navigation:navigation-ui-ktx:$navigationVersion" 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 - implementation 'com.google.code.gson:gson:2.8.7' + implementation 'com.google.code.gson:gson:2.8.8' // OpenStreetMap - implementation 'org.osmdroid:osmdroid-android:6.1.10' + implementation 'org.osmdroid:osmdroid-android:6.1.11' } diff --git a/app/src/main/java/org/y20k/trackbook/Keys.kt b/app/src/main/java/org/y20k/trackbook/Keys.kt index b9397ac..79dbc81 100644 --- a/app/src/main/java/org/y20k/trackbook/Keys.kt +++ b/app/src/main/java/org/y20k/trackbook/Keys.kt @@ -91,6 +91,9 @@ object Keys { const val TEMP_FILE: String = "temp.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 val DEFAULT_DATE: Date = Date(0L) @@ -108,7 +111,7 @@ object Keys { const val DEFAULT_ACCURACY: Float = 300f // in meters const val DEFAULT_ALTITUDE: Double = 0.0 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_AGE: Long = 60000000000L // one minute in nanoseconds const val DEFAULT_THRESHOLD_DISTANCE: Float = 15f // 15 meters diff --git a/app/src/main/java/org/y20k/trackbook/MapFragment.kt b/app/src/main/java/org/y20k/trackbook/MapFragment.kt index 29cd30e..50206b7 100644 --- a/app/src/main/java/org/y20k/trackbook/MapFragment.kt +++ b/app/src/main/java/org/y20k/trackbook/MapFragment.kt @@ -22,10 +22,7 @@ import android.Manifest import android.content.* import android.content.pm.PackageManager import android.location.Location -import android.os.Build -import android.os.Bundle -import android.os.Handler -import android.os.IBinder +import android.os.* import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -55,7 +52,7 @@ class MapFragment : Fragment(), YesNoDialog.YesNoDialogListener, MapOverlayHelpe /* Main class variables */ 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 gpsProviderActive: Boolean = false private var networkProviderActive: Boolean = false diff --git a/app/src/main/java/org/y20k/trackbook/SettingsFragment.kt b/app/src/main/java/org/y20k/trackbook/SettingsFragment.kt index da30fd1..7131b8b 100644 --- a/app/src/main/java/org/y20k/trackbook/SettingsFragment.kt +++ b/app/src/main/java/org/y20k/trackbook/SettingsFragment.kt @@ -116,15 +116,15 @@ class SettingsFragment : PreferenceFragmentCompat(), YesNoDialog.YesNoDialogList preferenceRecordingAccuracy.setDefaultValue(false) // set up "Altitude Smoothing" preference - val preferenceAltitudeSmoothingValue: SeekBarPreference = SeekBarPreference(activity as Context) - preferenceAltitudeSmoothingValue.title = getString(R.string.pref_altitude_smoothing_value_title) - preferenceAltitudeSmoothingValue.setIcon(R.drawable.ic_bar_chart_24) - preferenceAltitudeSmoothingValue.key = Keys.PREF_ALTITUDE_SMOOTHING_VALUE - preferenceAltitudeSmoothingValue.summary = getString(R.string.pref_altitude_smoothing_value_summary) - preferenceAltitudeSmoothingValue.showSeekBarValue = true - preferenceAltitudeSmoothingValue.min = Keys.MIN_NUMBER_OF_WAYPOINTS_FOR_ELEVATION_CALCULATION - preferenceAltitudeSmoothingValue.max = Keys.MAX_NUMBER_OF_WAYPOINTS_FOR_ELEVATION_CALCULATION - preferenceAltitudeSmoothingValue.setDefaultValue(Keys.DEFAULT_ALTITUDE_SMOOTHING_VALUE) +// val preferenceAltitudeSmoothingValue: SeekBarPreference = SeekBarPreference(activity as Context) +// preferenceAltitudeSmoothingValue.title = getString(R.string.pref_altitude_smoothing_value_title) +// preferenceAltitudeSmoothingValue.setIcon(R.drawable.ic_bar_chart_24) +// preferenceAltitudeSmoothingValue.key = Keys.PREF_ALTITUDE_SMOOTHING_VALUE +// preferenceAltitudeSmoothingValue.summary = getString(R.string.pref_altitude_smoothing_value_summary) +// preferenceAltitudeSmoothingValue.showSeekBarValue = true +// preferenceAltitudeSmoothingValue.min = Keys.MIN_NUMBER_OF_WAYPOINTS_FOR_ELEVATION_CALCULATION +// preferenceAltitudeSmoothingValue.max = Keys.MAX_NUMBER_OF_WAYPOINTS_FOR_ELEVATION_CALCULATION +// preferenceAltitudeSmoothingValue.setDefaultValue(Keys.DEFAULT_ALTITUDE_SMOOTHING_VALUE) // set up "Reset" preference @@ -135,7 +135,7 @@ class SettingsFragment : PreferenceFragmentCompat(), YesNoDialog.YesNoDialogList preferenceResetAdvanced.setOnPreferenceClickListener{ // reset "Recording Accuracy" preference preferenceRecordingAccuracy.isChecked = false - preferenceAltitudeSmoothingValue.value = Keys.DEFAULT_ALTITUDE_SMOOTHING_VALUE +// preferenceAltitudeSmoothingValue.value = Keys.DEFAULT_ALTITUDE_SMOOTHING_VALUE return@setOnPreferenceClickListener true } @@ -181,7 +181,7 @@ class SettingsFragment : PreferenceFragmentCompat(), YesNoDialog.YesNoDialogList val preferenceCategoryAdvanced: PreferenceCategory = PreferenceCategory(activity as Context) preferenceCategoryAdvanced.title = getString(R.string.pref_advanced_title) preferenceCategoryAdvanced.contains(preferenceRecordingAccuracy) - preferenceCategoryAdvanced.contains(preferenceAltitudeSmoothingValue) +// preferenceCategoryAdvanced.contains(preferenceAltitudeSmoothingValue) preferenceCategoryAdvanced.contains(preferenceResetAdvanced) val preferenceCategoryAbout: PreferenceCategory = PreferenceCategory(context) @@ -198,7 +198,7 @@ class SettingsFragment : PreferenceFragmentCompat(), YesNoDialog.YesNoDialogList screen.addPreference(preferenceDeleteNonStarred) screen.addPreference(preferenceCategoryAdvanced) screen.addPreference(preferenceRecordingAccuracy) - screen.addPreference(preferenceAltitudeSmoothingValue) +// screen.addPreference(preferenceAltitudeSmoothingValue) screen.addPreference(preferenceResetAdvanced) screen.addPreference(preferenceCategoryAbout) screen.addPreference(preferenceAppVersion) diff --git a/app/src/main/java/org/y20k/trackbook/TrackerService.kt b/app/src/main/java/org/y20k/trackbook/TrackerService.kt index f88cdc8..097145b 100644 --- a/app/src/main/java/org/y20k/trackbook/TrackerService.kt +++ b/app/src/main/java/org/y20k/trackbook/TrackerService.kt @@ -32,10 +32,7 @@ import android.hardware.SensorManager import android.location.Location import android.location.LocationListener import android.location.LocationManager -import android.os.Binder -import android.os.Bundle -import android.os.Handler -import android.os.IBinder +import android.os.* import androidx.core.content.ContextCompat import kotlinx.coroutines.* import kotlinx.coroutines.Dispatchers.IO @@ -69,7 +66,7 @@ class TrackerService: Service(), SensorEventListener { var networkLocationListenerRegistered: Boolean = false var bound: Boolean = false 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 lateinit var locationManager: LocationManager private lateinit var sensorManager: SensorManager @@ -97,7 +94,7 @@ class TrackerService: Service(), SensorEventListener { trackingState = PreferencesHelper.loadTrackingState() currentBestLocation = LocationHelper.getLastKnownLocation(this) track = FileHelper.readTrack(this, FileHelper.getTempFileUri(this)) - altitudeValues.capacity = PreferencesHelper.loadAltitudeSmoothingValue() +// altitudeValues.capacity = PreferencesHelper.loadAltitudeSmoothingValue() PreferencesHelper.registerPreferenceChangeListener(sharedPreferenceChangeListener) } @@ -577,16 +574,16 @@ class TrackerService: Service(), SensorEventListener { } - // TODO remove - val testAltitudes: Array = 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 - fun getTestAltitude(): Double { - if (testCounter >= testAltitudes.size) testCounter = 0 - val testAltitude: Double = testAltitudes[testCounter] - testCounter ++ - return testAltitude - } - // TODO remove +// // TODO remove +// val testAltitudes: Array = 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 +// fun getTestAltitude(): Double { +// if (testCounter >= testAltitudes.size) testCounter = 0 +// val testAltitude: Double = testAltitudes[testCounter] +// testCounter ++ +// return testAltitude +// } +// // TODO remove } diff --git a/app/src/main/java/org/y20k/trackbook/TracklistFragment.kt b/app/src/main/java/org/y20k/trackbook/TracklistFragment.kt index a843817..c349400 100644 --- a/app/src/main/java/org/y20k/trackbook/TracklistFragment.kt +++ b/app/src/main/java/org/y20k/trackbook/TracklistFragment.kt @@ -84,7 +84,7 @@ class TracklistFragment : Fragment(), TracklistAdapter.TracklistAdapterListener, val swipeHandler = object : UiHelper.SwipeToDeleteCallback(activity as Context) { override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { // 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)}" 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)) // toggle onboarding layout - toggleOnboardingLayout(tracklistAdapter.itemCount) + toggleOnboardingLayout() return rootView } @@ -118,7 +118,7 @@ class TracklistFragment : Fragment(), TracklistAdapter.TracklistAdapterListener, when (dialogResult) { // user tapped remove track true -> { - toggleOnboardingLayout(tracklistAdapter.itemCount -1) + toggleOnboardingLayout() tracklistAdapter.removeTrackAtPosition(activity as Context, payload) } // user tapped cancel @@ -132,8 +132,8 @@ class TracklistFragment : Fragment(), TracklistAdapter.TracklistAdapterListener, // toggle onboarding layout - private fun toggleOnboardingLayout(trackCount: Int) { - when (trackCount == 0) { + private fun toggleOnboardingLayout() { + when (tracklistAdapter.isEmpty()) { true -> { // show onboarding layout tracklistOnboarding.visibility = View.VISIBLE @@ -166,7 +166,7 @@ class TracklistFragment : Fragment(), TracklistAdapter.TracklistAdapterListener, if (deleteTrackId != -1L) { CoroutineScope(Main). launch { tracklistAdapter.removeTrackById(this@TracklistFragment.activity as Context, deleteTrackId) - toggleOnboardingLayout(tracklistAdapter.itemCount - 1) + toggleOnboardingLayout() } } } diff --git a/app/src/main/java/org/y20k/trackbook/dialogs/YesNoDialog.kt b/app/src/main/java/org/y20k/trackbook/dialogs/YesNoDialog.kt index be693e5..68aa40c 100644 --- a/app/src/main/java/org/y20k/trackbook/dialogs/YesNoDialog.kt +++ b/app/src/main/java/org/y20k/trackbook/dialogs/YesNoDialog.kt @@ -84,7 +84,7 @@ class YesNoDialog (private var yesNoDialogListener: YesNoDialogListener) { } // handle outside-click as "no" - builder.setOnCancelListener{ + builder.setOnCancelListener { yesNoDialogListener.onYesNoDialog(type, false, payload, payloadString) } 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 6b92289..74a76b1 100644 --- a/app/src/main/java/org/y20k/trackbook/helpers/FileHelper.kt +++ b/app/src/main/java/org/y20k/trackbook/helpers/FileHelper.kt @@ -182,9 +182,9 @@ object FileHelper { val tracklist: Tracklist = readTracklist(context) tracklist.tracklistElements.add(track.toTracklistElement(context)) tracklist.totalDistanceAll += track.length - tracklist.totalDurationAll += track.duration - tracklist.totalRecordingPausedAll += track.recordingPaused - tracklist.totalStepCountAll += track.stepCount +// tracklist.totalDurationAll += track.duration // note: TracklistElement does not contain duration +// tracklist.totalRecordingPausedAll += track.recordingPaused // note: TracklistElement does not contain recordingPaused +// tracklist.totalStepCountAll += track.stepCount // note: TracklistElement does not contain stepCount cont.resume(saveTracklist(context, tracklist, modificationDate)) } } @@ -340,6 +340,8 @@ object FileHelper { // delete track files tracklistElement.trackUriString.toUri().toFile().delete() tracklistElement.gpxUriString.toUri().toFile().delete() + // subtract track length from total distance + tracklist.totalDistanceAll -= tracklistElement.length } tracklist.tracklistElements.removeAll{ tracklistElements.contains(it) } saveTracklist(context, tracklist, GregorianCalendar.getInstance().time) @@ -353,6 +355,8 @@ object FileHelper { // delete track files tracklistElement.trackUriString.toUri().toFile().delete() tracklistElement.gpxUriString.toUri().toFile().delete() + // subtract track length from total distance + tracklist.totalDistanceAll -= tracklistElement.length // remove track element from list tracklist.tracklistElements.removeIf { TrackHelper.getTrackId(it) == TrackHelper.getTrackId(tracklistElement) } saveTracklist(context, tracklist, GregorianCalendar.getInstance().time) 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 5824b51..a2e27e8 100644 --- a/app/src/main/java/org/y20k/trackbook/helpers/PreferencesHelper.kt +++ b/app/src/main/java/org/y20k/trackbook/helpers/PreferencesHelper.kt @@ -87,19 +87,19 @@ object PreferencesHelper { return sharedPreferences.getBoolean(Keys.PREF_GPS_ONLY, false) } - /* Loads accuracy threshold used to determine if location is good enough */ - fun loadAccuracyThreshold(): Int { - // load tracking state - return sharedPreferences.getInt(Keys.PREF_LOCATION_ACCURACY_THRESHOLD, Keys.DEFAULT_THRESHOLD_LOCATION_ACCURACY) - } +// /* Loads accuracy threshold used to determine if location is good enough */ +// fun loadAccuracyThreshold(): Int { +// // load tracking state +// return sharedPreferences.getInt(Keys.PREF_LOCATION_ACCURACY_THRESHOLD, Keys.DEFAULT_THRESHOLD_LOCATION_ACCURACY) +// } - /* Loads state of recording accuracy */ - fun loadRecordingAccuracyHigh(): Boolean { - // load current setting - return sharedPreferences.getBoolean(Keys.PREF_RECORDING_ACCURACY_HIGH, false) - } +// /* Loads state of recording accuracy */ +// fun loadRecordingAccuracyHigh(): Boolean { +// // load current setting +// return sharedPreferences.getBoolean(Keys.PREF_RECORDING_ACCURACY_HIGH, false) +// } /* Loads current accuracy multiplier */ @@ -111,11 +111,11 @@ object PreferencesHelper { } - /* Load altitude smoothing value */ - fun loadAltitudeSmoothingValue(): Int { - // load current setting - return sharedPreferences.getInt(Keys.PREF_ALTITUDE_SMOOTHING_VALUE, Keys.DEFAULT_ALTITUDE_SMOOTHING_VALUE) - } +// /* Load altitude smoothing value */ +// fun loadAltitudeSmoothingValue(): Int { +// // load current setting +// return sharedPreferences.getInt(Keys.PREF_ALTITUDE_SMOOTHING_VALUE, Keys.DEFAULT_ALTITUDE_SMOOTHING_VALUE) +// } /* Loads the state of a map */ 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 41dc59f..d8588d0 100644 --- a/app/src/main/java/org/y20k/trackbook/helpers/TrackHelper.kt +++ b/app/src/main/java/org/y20k/trackbook/helpers/TrackHelper.kt @@ -44,13 +44,11 @@ object TrackHelper { /* Returns unique ID for Track - currently the start date */ - fun getTrackId(track: Track): Long = - track.recordingStart.time + fun getTrackId(track: Track): Long = track.recordingStart.time /* Returns unique ID for TracklistElement - currently the start date */ - fun getTrackId(tracklistElement: TracklistElement): Long = - tracklistElement.date.time + fun getTrackId(tracklistElement: TracklistElement): Long = tracklistElement.date.time /* Adds given locatiom as waypoint to track */ @@ -258,20 +256,20 @@ object TrackHelper { fun calculateAndSaveTrackTotals(context: Context, tracklist: Tracklist) { CoroutineScope(IO).launch { var totalDistanceAll: Float = 0f - var totalDurationAll: Long = 0L - var totalRecordingPausedAll: Long = 0L - var totalStepCountAll: Float = 0f +// var totalDurationAll: Long = 0L +// var totalRecordingPausedAll: Long = 0L +// var totalStepCountAll: Float = 0f tracklist.tracklistElements.forEach { tracklistElement -> val track: Track = FileHelper.readTrack(context, tracklistElement.trackUriString.toUri()) totalDistanceAll += track.length - totalDurationAll += track.duration - totalRecordingPausedAll += track.recordingPaused - totalStepCountAll += track.stepCount +// totalDurationAll += track.duration +// totalRecordingPausedAll += track.recordingPaused +// totalStepCountAll += track.stepCount } tracklist.totalDistanceAll = totalDistanceAll - tracklist.totalDurationAll = totalDurationAll - tracklist.totalRecordingPausedAll = totalRecordingPausedAll - tracklist.totalStepCountAll = totalStepCountAll +// tracklist.totalDurationAll = totalDurationAll +// tracklist.totalRecordingPausedAll = totalRecordingPausedAll +// tracklist.totalStepCountAll = totalStepCountAll FileHelper.saveTracklistSuspended(context, tracklist, GregorianCalendar.getInstance().time) } } 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 14f3b1b..9148f18 100644 --- a/app/src/main/java/org/y20k/trackbook/helpers/UiHelper.kt +++ b/app/src/main/java/org/y20k/trackbook/helpers/UiHelper.kt @@ -29,6 +29,7 @@ import androidx.core.content.ContextCompat import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.RecyclerView import org.y20k.trackbook.R +import org.y20k.trackbook.tracklist.TracklistAdapter /* @@ -101,6 +102,12 @@ object UiHelper { 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) { val itemView = viewHolder.itemView val itemHeight = itemView.bottom - itemView.top 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 7e4bd57..6c4404b 100644 --- a/app/src/main/java/org/y20k/trackbook/tracklist/TracklistAdapter.kt +++ b/app/src/main/java/org/y20k/trackbook/tracklist/TracklistAdapter.kt @@ -32,6 +32,7 @@ import androidx.recyclerview.widget.RecyclerView import kotlinx.coroutines.* import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.Main +import org.y20k.trackbook.Keys import org.y20k.trackbook.R import org.y20k.trackbook.core.Tracklist import org.y20k.trackbook.core.TracklistElement @@ -78,49 +79,89 @@ 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) + } + } + } + + + /* 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 */ override fun getItemCount(): Int { - return tracklist.tracklistElements.size + // +1 ==> the total statistics element + return tracklist.tracklistElements.size + 1 } /* Overrides onBindViewHolder from RecyclerView.Adapter */ override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { - val trackElementViewHolder: TrackElementViewHolder = holder as TrackElementViewHolder - trackElementViewHolder.trackNameView.text = tracklist.tracklistElements[position].name - trackElementViewHolder.trackDataView.text = createTrackDataString(position) - when (tracklist.tracklistElements[position].starred) { - true -> trackElementViewHolder.starButton.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_star_filled_24dp)) - false -> trackElementViewHolder.starButton.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_star_outline_24dp)) - } - trackElementViewHolder.trackElement.setOnClickListener { - tracklistListener.onTrackElementTapped(tracklist.tracklistElements[position]) - } - trackElementViewHolder.starButton.setOnClickListener { - toggleStarred(it, position) + + when (holder) { + + // CASE STATISTICS ELEMENT + is ElementStatisticsViewHolder -> { + val elementStatisticsViewHolder: ElementStatisticsViewHolder = holder as ElementStatisticsViewHolder + elementStatisticsViewHolder.totalDistanceView.text = LengthUnitHelper.convertDistanceToString(tracklist.totalDistanceAll, useImperial) + } + + // CASE TRACK ELEMENT + is ElementTrackViewHolder -> { + 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 */ - fun getTrackName(position: Int): String { - return tracklist.tracklistElements[position].name + fun getTrackName(positionInRecyclerView: Int): String { + // first position is always the statistics element + return tracklist.tracklistElements[positionInRecyclerView - 1].name } /* Removes track and track files for given position - used by TracklistFragment */ fun removeTrackAtPosition(context: Context, position: Int) { CoroutineScope(IO).launch { - val deferred: Deferred = async { FileHelper.deleteTrackSuspended(context, position, tracklist) } + val positionInTracklist = position - 1 + val deferred: Deferred = async { FileHelper.deleteTrackSuspended(context, positionInTracklist, tracklist) } // wait for result and store in tracklist withContext(Main) { tracklist = deferred.await() - notifyItemRemoved(position) } + notifyItemRemoved(position) + notifyItemChanged(0) + } } } @@ -130,16 +171,25 @@ class TracklistAdapter(private val fragment: Fragment) : RecyclerView.Adapter = async { FileHelper.deleteTrackSuspended(context, position, tracklist) } + val positionInTracklist: Int = findPosition(trackId) + val deferred: Deferred = async { FileHelper.deleteTrackSuspended(context, positionInTracklist, tracklist) } // wait for result and store in tracklist withContext(Main) { 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 */ private fun findPosition(trackId: Long): Int { tracklist.tracklistElements.forEachIndexed {index, tracklistElement -> @@ -215,11 +265,23 @@ class TracklistAdapter(private val fragment: Fragment) : RecyclerView.Adapter + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/track_element.xml b/app/src/main/res/layout/element_track.xml similarity index 100% rename from app/src/main/res/layout/track_element.xml rename to app/src/main/res/layout/element_track.xml diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ee1db1f..18a5c15 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -72,6 +72,8 @@ Your recorded tracks … will show up here. + + Total Distance Recorded About Version @@ -124,4 +126,5 @@ 23.0 km • 5 hrs 23 min 42 sec July 20, 1969 track data missing + 6357.23 km diff --git a/build.gradle b/build.gradle index 1664257..2cd83f8 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ buildscript { ext { - kotlin_version = '1.5.20' + kotlin_version = '1.5.30' navigation_version = '2.3.3' } repositories { @@ -10,7 +10,7 @@ buildscript { mavenCentral() } 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 "androidx.navigation:navigation-safe-args-gradle-plugin:$navigation_version" diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1f3fdbc..29e4134 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME 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 zipStorePath=wrapper/dists