Would it be a difficult task to enable an option in the repository settings in the Android app that would post a system notification when that repo is modified by another node? This simple feature would add tremendous value to the Syncthing app, because currently there is no convenient way for someone sharing a repository with others to know that someone else added or changed a file.
I would love to be able to distribute photos and videos to my family and friends by simply adding them to a shared repository where they would be automatically notified. Or if Iām collaborating on a document, it would be nice to efficiently know when updates are made.
Oh, I forgot to search the GitHub issues before posting. Itās still not reading those threads how to implement the feature. Could you sketch some details about the functions that should be modified? I might be able to do it myself if I have some starting guidance.
It appears that we have a choice either to (1) add the functionality to the Android app itself or (2) add it to Syncthing and create an additional REST API that the app uses to check for changes to the specified repos in order to issue a system notification. It would seem that (2) is the better option since this notification feature would be useful across platforms.
@anaqreon So youād add a getEvents(int id) to RestApi. That function does the API request and parses the JSON into a new, appropriate Java object (like RestApi.Device).
Then you add functionality to SyncthingService to poll that function and create notifications on change. Also, there should be a setting to enable this (imo it should be off by default).
I think Iāve got a decent handle on the first half of your outline. I have a RestApi.SyncEvent static class that should contain the information in each event returned by the /rest/events API. I created a listener interface class that takes a list of SyncEvent objects and does⦠something. Now I need guidance on how to implement that listener function in SyncthingService.java to actually do something with the information.
Is this Event API something that has to be polled at some fixed frequency (like every 30-60 sec)? Iām guessing that somehow SyncthingService will need a variable that keeps track of the last SyncEvent ID to minimize the data transfer and parsing.
Event API takes some query parameters (I think since=N or last=M) to indicate that you are interested in events older than N or last M events available.
If there arenāt any events, the call will block up for up to a minute after which it will time out and should be retried.
I created a polling function as you suggested and made SyncthingService implement a listener interface class to get the list of recent events. Hereās the latest code. I have minimal experience with Java, so what Iāve done so far needs some detailed review so I donāt do something too stupid.
The next step is to analyze the list of returned SyncEvent objects and (1) identify events that mean a new file has been added to a specified repo and (2) issue an Android system notification to the user. Right now I donāt have a clue how to do either of those things, so more suggestions are welcome!
I donāt think there is a āA file has been addedā event, but there is āRemoteIndexChangedā which means that we will start downloading stuff as something has changed on a remote node. You can track files with āDownloadProgressā event but this might be excessive as itās per file, and given you have 200new files added, that means 200 notifications.
The use case in mind is a repo that doesnāt get updates or modifications very often, like the photo sharing example I mentioned. When many files are added, they are typically added at once. Perhaps the plan should be to check very infrequently (5-10 min) so that it is easier to reduce the quantity of notifications by summarizing/compacting a something like 200 new files with a single notification that says ā200 files addedā.
The code looks good to me. Only thing I would change is inline the SyncthingService#getEvents() function (itās a two-liner thatās only called from one place).
Have you thought about what action the notification should have? I suppose it should show a dialog listing the changed files, maybe with an option to open/view them. Or open the directory/file directly for a single change.
Update: Using the CatLog app I can see that I am indeed retrieving events periodically as the timer fires, so thatās progress! Now itās on to the actual notification mechanism. Iām going to start with something vague and simple like āSomething changed in one of your reposā. Then weāll need to design a way for the user to (1) toggle the notification feature and (2) specify the repos for which they want notifications.
By the way, when I pull the latest updates from upstream, is there a way to have git automatically checkout the current syncthing subproject tag? I have to manually check the commit history to see that, for example, you bumped it up to v0.10.11.
Iām not sure if we need a per-repo setting for notifications, could be too much clutter. For the global preference, you want to edit SettingsFragment and app_settings.xml (have a look at the ALWAYS_RUN_IN_BACKGROUND preference and copy that).
For the submodule, thereās an answer on stackoverflow.
Btw itās probably more convenient to use adb logcat or the logcat view in Android Studio
Thanks for the links and guidance. I create a simple notification toggle setting that seems like it should work but doesnāt. You should check that the method of using the onApiChange() function for stopping and starting the timer that fires the event poller is the sensible thing to do.
I disagree that a global preference like this āfirst draftā learning effort is sufficient. Some repos might have frequent updates due to some automated process that the user has no desire to be notified about, while one or two of their other repos are folders shared among friends and family for social networking purposes, in which case they do want the handful of notifications they might receive per day. To implement this, should we add an additional toggle setting in the folder settings (FolderSettingsFragment.java)? Weāll have to access this list after parsing each set of retrieved events to determine whether or not to issue a notification.
Not sure what you mean about onApiChange(), I canāt see any differences in that method.
The thing about different repos is probably true, I donāt have many repos personally. In that case, thereās really no point to the global preference, so Iād just add the preference to FolderSettingsFragment. You can then save the setting to an Android preference like ānotifiy_on_change-reponameā. And then enable polling if this is true for at least one repo.
Making progress, but still working on the basics. I corrected the problem with the global setting, so it works now. When events are retrieved, a notification is issued that the user can see in the notification area, and currently clicking the notification simply opens MainActivity. The problem is that once the user dismisses the notification, it does not reappear when the next retrieval occurs.
Now Iām ready to actually parse the event list and search for the repo update of interest. It looks like the DownloadProgress event is the way to go. It has the information about which files in which folders are being downloaded, so this can be stored in a cache until the downloads complete, at which time a specific notification can be generated if the downloaded file is in the user-specified repo.
The last part of this notification functionality I want to complete is what happens after the user is notified. I would like to have the notification open Syncthing when tapped, and prompt the user to open the file with whatever installed app is available to do so.
For reappearing, there are some settings on Notification.Builder (though I donāt see anything relevant right now). Also, youāre supposed to use a hardcoded notification id, not a random value
You could also directly open the file/folder with an intent (like here). But youād still need a list if there are multiple files. Imo a dialog would be best UX-wise.