Widget getTimeline method called multiple times for customized intents - ios

In my iOS 14 widget with a single custom intent, when the user selects one intent, then changes to another, my getTimeline method is called multiple times for each intent on each refresh - including previously-selected ones.
I would expect getTimeline to only be called with the currently-selected intent. Is there a way to check whether the intent is the currently-selected intent? I make a network request in the getTimeline method and I do not want to make multiple requests when the widget only shows one intent.
As an example, I downloaded the Emoji Ranger sample code and added a print statement to the getTimeline method. I then:
Run the app and open it once.
Add a widget to the home screen.
Run the widget extension target on the simulator.
Select the character Egghead.
Select the character Cake.
This is what prints on the next widget refresh (usually ~15 mins):
- Timeline: nil
- Timeline: Optional("Egghead")
- Timeline: Optional("Cake")
Any help is much appreciated, thanks!

Related

How to query WidgetKit if my widgets are being used?

I would like to check if the user added my widgets to the Home Screen, is there an API for this? I could not find one. WidgetCenter.getCurrentConfigurations returns all available widgets served by the app, not the used ones.
The reasons I look for such an API are:
I would like to report usages of the widgets.
I would like to decide if I should trigger timeline reloads via WidgetCenter when state changes happen in the app.
Method WidgetCenter.shared.getCurrentConfigurations does return the number of user configured widgets:
WidgetCenter.shared.getCurrentConfigurations { widgets
if let widgets = widgets, widgets.count > 0 {
// User did configure at least one widgets
}
}
This is also according the documentation:
Retrieves information about user-configured widgets.
Unfortunately, I don't think such an API exists (yet).
For 1. I would write something that identifies the widget in a shared user defaults container. Hooks for that would be getSnapshot(for:,in:,completion:) or getTimeline(for:,in:,completion:) with context.isPreview == false. Now the difficult part is that you don't get any id for the widget so you cannot distinguish two widgets with the same configuration (afaik).
For 2. I think this is (and will be) opaque, so you just tell the WidgetCenter to reload specific or all configurations and when no widget is currently placed on the home screen nothing happens.

Firebase Database doesn't return value offline

I'm working on a app with Firebase Database and I also want to allow the user adding entries when he's offline. Imagine the following case (everything offline; it works perfectly online):
The user adds a client (shown in a main tableview - works)
On the detail view of the freshly added client, he adds an appointment with him. The appointments are listed in a tableview in the Client Detail ViewController.
When the appointment is added, the tableview isn't refreshed, because the callback doesn't call.
In code:
navCont.child = userDB.child(entityNameClients).childByAutoId()
navCont.child?.setValue(post) where post is a dictionary with the values of the customer
On the viewDidLoad Method of the detail view controller, I call the following code: getUsersDBReference().child(entityNameAppointments).child(clientKey).observe(.value). The Callback isn't called (probably because there are no elements in it)
Adding Appointment
var appointment:DatabaseReference
appointment = getUsersDBReference().child(entityNameAppointments).child(clientKey).childByAutoId()
appointment.setValue(appointmentDict)
The Callback of 2 isn't called (--> and the tableview not refreshed with the new appointment)
BTW, I set Database.database().isPersistenceEnabled = true in App Delegates applicationDidLoad-method.
And if I add the client online and go offline then, it works too.
Answer of Firebase Support:
The SDK attempts not to fire Value events with "partial" data. Since you are only updating a subnode of the location being observed, we don't have "complete" data and so the observer is not fired. If the SDK has ever had "complete" data for that node (e.g. because you overwrote the whole node or because you were previously online and got complete data for it), then it will fire events when you update it.
One workaround would be to use ChildAdded (and ChildChanged, etc.) events instead of Value.

WKInterfacePicker setValue and pickerAction infinite loop

Main app sends data to watch, and watch sets the picker index by using:
[picker setSelectedItemIndex:val];
This in turn, will fire up the picker action. However my picker action sends data to phone (using sendMessage) which in turn replies back to watch... and that goes on forever.
How can I cancel the picker action for setSelectedItemIndex:? WKInterfacePicker doesn't have a removeTarget: method.
You don't want to remove the action. Instead, you have a few options to choose from to simply stop the cycle from happening by:
Only setting the picker's value when the initial message is received, not when the response is received.
If the watch says, "The picker index is 3," and the phone replies, "Roger, the picker was set to 3," why would you want your watch code to set the picker based on the response to something the watch initially sent? This seems to be the crux of the issue, and would be the optimum solution.
Use a different key for the response, if necessary, to help any shared code distinguish between the types of messages.
Not setting (or sending) the picker's value, when it already matches the picker's current selected index.
You'd have to maintain a property to keep track of the current value, as the picker's properties are write-only and can't be read.
Using a different WCSession method (such as updateApplicationContext) which is designed not to resend data when it matches the most recent applicationContext.

Show notification after a CSV file has been fully exported with Vaadin

I have the following code:
Button export = new Button("CSV");
export.addListener(new ClickListener()
{
public void buttonClick(ClickEvent event)
{
CsvExport csvExport;
csvExport = new CsvExport(_table);
csvExport.setDisplayTotals(false);
csvExport.setDoubleDataFormat("0");
csvExport.excludeCollapsedColumns();
csvExport.setReportTitle("Document title");
csvExport.setExportFileName("Nome_file_example.csv");
csvExport.export();
getWindow().showNotification("Document saved", "The document has been exported.");
}
}
I would like the notification to appear only after the file has been exported and downloaded, but actually the notification is not working, maybe because it does not "wait" for the statement
csvExport.export();
to finish. If I comment it, the notification works.
Does anybody have any suggestions?
Thanks very much,
You'll need to split the work into a separate thread, then provide a way to notify the user 'later'.
So, first, create a thread... if you're on Java EE, use the built-in thread pooling, otherwise use something else (we're on tomcat, we rolled our own, to allow us better control).
Then, when you're done, synchronize your thread, work your way back into your UI class (We use closures from Groovy, but you can make your own listener), and call the method to notify your user. window.showNotification('All Done')
So here's the tricky part, you've notified your user, but Vaadin has already sent the 'click' response back... so the Server part thinks it's notified the user, but it isn't able to show the user yet... You'll need a progress indicator on your page, as it asks the server every 5 seconds if anything has changed.
There are also some 'push' plugins, but I've found that most of the places that we we're spinning up threads, we want to show a 'loading' animation, so the progress indicator works well.

iOS Managing Async Blocks for Remote Requests

Not sure how to best explain this - If I use blocks to load images for UITableViewCells, how best can I ensure that when an image actually finishes loading - it is the correct image for the cell. Say I'm making an app with user icons - so cell 5 is for John and it starts loading John's image. Say that request gets hung up and by the time it returns, that cell has been reused for Bill at cell 23. We obviously don't want to load John's icon - we just want Bill's.
This is a simplified explanation. I know that we can check if a cell is visible in the block before setting the image - but say in a different scenario I have a method that makes a remote request when called. When the remote request is done, it calls a block defined in that method that updates the UI. If I call it and before it returns I call it again and only want the most recent call's block executed. Is there a good pattern for doing this?
Currently, I try to store a variable that has some state in the method so that when it returns I can check if that state is still valid. Just thought I'd see if there was a better way. Thanks.
Just checking if any updates on this.

Resources