Writing KelpFT
2024-08-13
I have been using fitotrack for tracking my workouts since.. pretty much when I started cycling, about three years ago, and it has been... fine-ish. I am happy with the core functionality but i have three problems:
- Features that I don't need (can be ignored)
- I don't like how it looks
- I need a simpler interface to start/stop workouts (or perhaps an automated interface for them even)
And so, considering that I have been itching to program something once again after writing [My first freewheeling application], I have a new mobile project in mind with this feature set:
- Basic workout tracking through GPS
- Workout-specific metadata that only I need/use
- Looks styled to my personal taste
- one tap to start a workout
- would track speed, elevation, total distance
- stop/start upon detecting no movement
- compatibility with other oss workout track formats, namely .gpx
- no 'native' support for workout types, i.e the workout type would just be a textfield, FitoTrack mostly uses this for calorie use calculation, which seems very inaccurate in my experience.
- Optimized for single-hand use, as i may be using it while having one hand on my bicycle
As for which tooling I should use for this.. I think i'll have to lean on flutter for this one. Although I wouldn't mind trying out jetpack compose.
I must say that trying to use LOVE for something like this will prove too difficult and time consuming, in my opinion.
2024-08-20
I've finally decided to commit a little bit harder to this as I have run out of other things to do at the moment.
I'm calling it 'KelpFT', it is going to be written in flutter.
I'm dividing my work into two rough fields. One for technical solutions and another for graphical screens.
The distinction is drawn there because these two sets are distinct in how i think about them. One set requires me to solve hard, practical puzzles essentially, while another requires less logical thought but more attention paid to how things look visually.
Technical solutions needed:
- A simple, globally accessible data layer for storing GPS track data
- GPX import/export, which means XML import/export, which may also mean interop with the data layer, not sure yet
- Attaching my own custom metadata to a GPX file
- A good OSM viewer + possibly a themed map? not sure about it yet
- A method for writing GPX data during a GPS track
- How to do GPS tracking in general
- How to derive statistics from a set of GPS tracking points.
- distance,
- avg speed
- elevation
- so on and so forth
- How to write an intent-based API for starting the workout (so i could maybe even start a workout by holding my samsung's bixby button)
Screens needed:
- Main training list. Shows all of your previous tracks, in a plain vertical list
- Training track view/statistic Shows the statistics of a particular track, and the route you took, on a map. Accessible from the main training list
- 'currently tracking' screen Is accessible from the main training list, enabled when you press a button to start a new track. TO BE OPTIMIZED FOR ONE HAND USE
- Settings screen Unsure if nessecary, accessible from main training list.
2024-08-29
And here we are, nine days later. I've been putting in a few hours from time to time into the app and i've gotten to the point where I am ready to begin basic field testing.
So, to put it simply, I ran into three major technical hurdles:
First off, It is not feasable to have a file-based data store for reading and writing and manipulating workouts. In other words, using a .gpx library (which I was fortunate to find) to read each and every file upon app start is not feasable. The reason being that there is simply too much overhead. In short, I ended up using the library to deserialize the files and noticed that it was taking far longer than I wish it did (think 3-5 seconds on an average phone). I was chalking it up to Flutter/Dart/the GPX library I used being too slow but honestly, .gpx files contain huge amounts of text. For reference, one of my four-hour-long endurance workouts chalk up to be a litte over 41 thousand lines of XML, and at this point i have about 50 of these files of varying length. No wonder it was taking too long. This essentialy left me with two choices:
- I try to somehow partially parse the .gpx files and only get the relevant information just-in-time, massively increasing complexity
- I switch to sqlite, which is a much better choice considering the amounts of data involved. I ended up doing the latter.
Second, google, as a company, is really, really getting in my way of just letting me write whatever program I want. The direction that android has been heading towards as of late has been abysmal. For one, they have been pushing a new geolocation API for a while now, that, for whatever reason, requires the google play services installed to use the local gps radio of your device. One of the flutter libraries that I was using in an attempt to get GPS geolocation working was relying said API. I had to learn that fun fact the hard way, since I am running LineageOS.
Luckily there is another flutter library for getting your location that instead relies on LocationManager for it's android implementation, which does not require any google services installed.
And last, My home, or rather, my room, is unable to receive GPS signals! I cannot test the core function of this application from the confines of my house. I'll need to conduct some more field testing.
What I've progressed on so far
Well, essentially, i've been putitng one to two hours every day into the app, and so far, I have:
- A basic UI
- A working openCycleMap-based map
- A working GPS recording mechanism, even when the phone's screen is off
- A fully fleshed out data model, including write/read methods into a local sqlite db.
- A working permission management service, a working setting management service
What I need to work on going forward
In terms of relevance:
- Removing the mapping API key from the codebase
- Uploading codebase to a remote git provider so that I can develop on a portable machine
- Methods of calculating average speed
- total distance
- A method to figure out if the user is moving or not
- A pause/resume system
- Field testing; ensuring that data gets written into the db properly
- A widget to display a workout (for the main list of workouts)
2024-09-01
Progress Update:
- The OCM API key has been moved into a build script that is under a .gitignore
- The codebase has been uploaded to sourcehut
- I have algorithms in place to calculate average speed and distance.
- The map now draws a line for where you went, and also centers on your last tracked position.
- The map is now fully cached, thanks to
flutter_map_tile_caching
I have also a few other things i'd like to address. For one, I am thinking of using something other than sqlite. At the end of the day, i was either going to go with an entirely filebased approach or a database-based approach, and if i'm picking a database, i might as well pick the one that is best suited for my needs and still maintain a common export format (gpx).
On top of that, since It makes for a much easier dev experience (you store objects directly, instead of converting them into SQL statements), I want to try using ObjectBox as my database, since I am not interested in being able to transfer data directly to and from the application any more, as that would be handled by .gpx import/export (I'll need a way to import/export in bulk).
2024-09-03
Progress Update:
- Did some additional field testing, was able to confirm that the app tracks my location accurately.
- Successfully switched to objectbox, which has an easier API to work with, which also reduced the size of my codebase, though it has a questionable license. I'm only overlooking that due to the fact that i'm making everything GPX-exportable anyways.
- Implemented a modal menu that allows the user to enter workout metadata upon pressing the 'stop workout' button
- Improvements to the workout display widgets
Hm, what do I need to do to deem this project complete for the time being?
- A workout view page, entered through a tap on a workout entry in the home page, containing:
- A map view of the route taken§
- A graph for speed
- A height graph,
- A workout edit page, entered from the workout view page, which allows me to edit
- workout location code
- workout comment
- Total distance traveled stats within home page
- A settings page? not sure if I have anything i'd like to be set
- A way to trigger a workout by holding down my phone's bixby button
- Improvements to the camera-following of the main recording page map view, it's inconsistent and generally mid asf
- A way to delete workouts
2024-09-07
Progress Update:
- Major annoyance bugfix, poorly documented behaviour led to objectbox relations being unusable, this took a lot of IRL testing (and therefore a lot of time) to figure out.
- Partial impl of workout view page
2024-09-09
It was somewhere at this point I decided to finally set a deadline for myself. Marking the 20th of this month as the day I declare the app 'done', which means that I gave myself a month to go from first line of code to completed project.
2024-09-11
It's the 11th as I am writing this and I am proud to say that I have been able to steadily make progress on the app for the last two weeks or so. At this point, 90% of the app's UI is fleshed out, I just need to draw a few additional icons, and make the last screen of the app, which just contains settings.
I am currently facing a dilemma when it comes to picking out the UI approach to delete workout entries. I am stuck between a plain 'longpress-to-delete' and 'swipe-to-delete'. After thinking about it for a bit, i'm leaning towards 'swipe-to-delete' because i've never done something like it before, and I want to add the technique to my arsenal.
2024-09-18
Unfortunately I ended up missing out on the last couple of days in terms of coding work due to spending one day celebrating a birthday and spending the next day after that doing yard work. What's even more angering is that I have also given myself a leg injury from said yard work, which has impaired my ability to walk/cycle for the next couple of days. I can write code for this app but I can't test it as well as i would wish.
So, it is the 18th as I am writing this. I have given myself 48 hours to finish this application, so far, I think i won't be missing too much.. The application, as it stands, still needs a fair bit of polish, but, as of now, what I have is:
- A mostly-working tracking system, only real issue is that it can get killed by android occasionally. Needs more long-term testing.
- A mostly-working data display system, needs better filtering of the inputs
- A fully working import/export backend
- A mostly-working import/export frontend. Still needs a button to export everything into a zip file.
Were I to think in terms of delivering an MVP, i would only really need a full backup functionality at this point, which can be achieved with a full .zip export of all of my workouts, and i'd also like some assurance in terms of the app not getting killed after a few hours of working out.
2024-09-20
Well, i've managed to achieve most of what I set out to do, import/export works, and I am forced to move on to other projects. The app is.. mostly there. I still need to re-reimplement the tracking API because it does not work reliably enough.
The source of the app can be found here