Open jotaen opened 3 years ago
There is also quite a common problem that the progress state appears to be flickering/flashing: the UI switches into loading state for just a split second, because the underlying operation executes very rapidly. This is inconvenient, because the user doesn’t get a chance to grasp what’s going on.
If the progress state was centrally controlled by the overlay panel, we could make it more sophisticated to account for that phenomenon. For example, the progress state could be debounced like so:
DialogProgressStarted
event fires, we wait for ~50–100ms. If DialogProgressFinished
was fired in the meantime, we just skip and don’t do anything. If it wasn’t fired, we switch to progress state. That way, we avoid visual flickering for fast operations altogether.
pointer-events: none
or so), so that the user cannot accidentally issue multiple clicks to the same button.DialogProgressFinished
had been fired earlier. That way the user always has enough time to follow the UI.(exact time values tbd; the event constructor could also take a boolean, such as DialogProgressEvent(true)
)
On a general note I think it’s not optimal that we currently tend to skip the loading states in order to avoid the flickering problem. The operations will for sure be very fast most of the time, but in case the network is delayed for example, the user doesn’t get any visual feedback that their command was received and is being processed.
On a general note I think it’s not optimal that we currently tend to skip the loading states in order to avoid the flickering problem.
I agree with this.
Idea: Computers are too fast. Let's slow everything down for humans. We could enforce a minimum amount of time a state can be active (i.e. loading screen must show for at least 1 sec) to give people time to "grasp what’s going on" 😆
I’d like to gently bump this ticket again. We recently worked on introducing a unified success state for dialogs, which already paved the road for extending the overlay with an additional, unified progress state.
As noted above, a unified and more robust progress state isn’t just a UI nicety, but it would also allow us to solve the dialog initialization issue, which currently is a tricky tradeoff between flickering and UI inconsistency.
For historical reference: the flickering issue stems from the fact that most operations within dialogs are usually pretty fast – e.g., network requests to the device backend. So if we display an intermediate “progress” state while these operations are in flight, then it might occur that this progress state appears and then disappears very rapidly again. This happens fast enough that the user is completely unable to read or visually process the progress state, but it’s still slow enough for the user to notice that something was briefly shown for a split second – see a demo of the “Hostname” dialog:
https://github.com/user-attachments/assets/ed4efa40-6b15-4290-9a40-059cc2560d4b
This might be quite confusing. In some instances, we therefore refrained from adding a progress state for certain operations, to “work around” this flickering problem. However, this can have an averse effect, e.g. if the user is on a slow network connection, which results in longer network latency. In this case, the UI might appear as stale/broken or non-responsive – such as in the “About” dialog or the “Hostname dialog”:
https://github.com/user-attachments/assets/4b2fc92f-8cd1-47d1-a149-2899b9fdea1c
https://github.com/user-attachments/assets/0351202d-8297-45c0-bd80-c78752176259
The “About” dialog displays blank fields while it’s fetching the info from the device backend, but it actually shouldn’t display anything at all yet. The “Hostname” dialog doesn’t appear to respond at all to the button click (though it actually had already started the operation under the hood), so it might come across as broken; in the worst case, the user clicks the button multiple times, which may result in erratic failures.
With a unified “progress” event (as outlined above), we could solve both the flickering issue and the UI styling.
As pointed out in https://github.com/mtlynch/tinypilot/pull/708, we could avoid some repetition in our dialog components by pulling out a generic progress state into the
<overlay-panel>
. The dialogs would emit eventsDialogProgressStarted
/DialogProgressFinished
that the overlay picks up and adjusts the visual state.That would not just make the code leaner, but it also ensures that the visual pattern is always consistent. In analogy to the error dialog, the progress state could have a blue top border and a slightly blue-ish background, so that the user recognises it easily.