thehale/SimpleTimeTracker-WearOS

Add a small round complication for the current activity(ies) and duration

Opened this issue · 8 comments

HH:MM is preferred over HH:MM:SS for battery saving purposes, though I'd welcome a setting to allow users to choose.

If the user is multi-tasking, the complication will list the number of active activities -- without naming them or their durations.

I have started working on the complication and I have something working with placeholder data.

Now I realized that this issue relies on #6, as it needs the same list of current activities to work.
So probably it makes sense to finish #6 first?

I have started working on the complication and I have something working with placeholder data.

Perfect!

Which types of complications do you have prototyped? On my watch at least there are large rectangles, small circles, and curved quarter arcs (I don't know the programming names for them yet, sorry!) Would love to see screenshots if you have them.

Now I realized that this issue relies on #6, as it needs the same list of current activities to work.

Correct. @kantarek has an open PR for that on #2 to unblock the communication layer.

As for now I started with the small circle type, which looks like this:
screenshot-2024-01-08-20-46-34

Great, looking forward to seeing this merged :)

Hi @christophstoeckl! It's nice to meet you.

I threw together this sequence diagram real quick to capture the overview of the main Wear<->Mobile interactions as they stand right now on my fork of Joseph's repo. Do you have insights as to how to get the data you need for rendering the complication? If things need to get moved around to facilitate it the sooner we know the better. I imagine we'll have the same question if & when we eventually design the Tile. At this point I'm guessing each UI workflow will end up using its own instance of MessagingFacade but I think we're open to other ideas.

image

And here's the tentative data model I've established for the "ACTION_ADHOC_EXPORT_CATEGORIES" response payload, again open to any more data your widget might need:

data class STTAdhocExportRecordModel constructor(
    val id: Long = 0,
    val name: String,
    val icon: String,
    @ColorInt val colorInt: Int = 0,
    val hidden: Boolean = false,
    var timeStarted: Long = -1,
    var comment: String = "",
)

Hi @kantahrek, nice to meet you too.

The diagram already looks very nice.
The complication gets its data from a ComplicationDataSourceService.
As it is a service I don't think it can have a ViewModel and hence it would be good if it could get the data from somewhere else. It's probably not a great idea to let the ComplicationDataSourceService use a MessagingFacade directly to get the data from the phone, as that would lead to polling and slow updates.

Perhaps it might be a good idea to introduce a repository layer, where all ViewModels and the ComplicationDataSourceService can get their data from, acting as a single source of truth and handling the communication with a MessagingFacade.
That way, one could also inform the complication directly if an activity has been started / stopped on the wear device.

About the data class, I think STTAdhocExportRecordModel should contain everything I need.
It doesn't really show much (mainly due to a lack of space) apart from the name, the time and the icon.

I like the idea of adding a repository in the Wear module from what I'm reading about the design pattern. Correct me if I'm wrong, but it sounds like the UI activity for the main app and the DataSourceService for the complication have two separate ingresses, and if we used DI we could more easily maintain a singleton of the Repository to share between them.

@thehale think it's time to pull in Dagger / DI of choice since we have multiple UIs now? I know it's hard to put that cat back in the bag once it's out.

Edit: I believe this question still applies even if we merge this repo into Razeeman's and do away with the intent exchanging, in which case we'd treat the MessagingFacade as a data source, just synchronous now.

Great discussion!

I've finally finished the core Wear -> Mobile communication layer between the WearOS app and the mobile app (see #8 for the latest sequence diagram), so we now have a reliable interface for polling the requested data. That said, we still need the implementation for WearRPCClient.queryCurrentActivities and DomainAPI.queryCurrentActivities for the data to flow correctly across that communication layer.

I can definitely support the creation of a repository to store the currently running activities on the watch. I imagine that would be another layer around the WearRPCClient to cache the currently running activity/activities instead of requesting them from the phone on each poll.

  • Successful calls to WearRPCClient.setCurrentActivities would update that cache.
  • I can add a Mobile -> Wear communication layer, e.g. for notifying the watch to update the cache based on changes made on the phone.
  • We'd probably still want some end-to-end polling. Since the underlying MessageClient doesn't guarantee message delivery, we'll need at least an infrequent sync to reach eventual consistency.

Regarding DI (Dependency Injection for the unfamiliar reader), I found it useful to apply DI via Hilt on the Mobile phone's WearableListenerService. Since we don't instantiate the service, a DI framework is the easiest way to get access to the "Interactors" which interface with the database. That said, all other injection was cleaner to conduct by simply passing objects around, no Hilt decorators required. I suspect the experience will be similar on the Watch -- use Hilt to inject a few key dependencies into the Service, but simply pass them around as normal function parameters/constructor arguments.

@christophstoeckl The communication APIs needed for this ticket are now stable and fully functional!

Here's an example of requesting the currently running activities, which I believe should be sufficient for the first version of your complication.