Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #11891 Enhanced Input Mode Detection for Hybrid Devices #11998

Merged

Conversation

poju3185
Copy link
Contributor

@poju3185 poju3185 commented Mar 19, 2024

Summary

Fix #11891
This Pull Request introduces an enhancement to the input mode detection logic for devices with both touch and mouse inputs. The core of this update is a global mouse click listener across the app, ensuring that once a mouse click is detected, Perseus will consistently render in standard mode. This approach simplifies the input mode logic and provides a more predictable user experience on hybrid devices.

References

https://stackoverflow.com/a/70827986 provided by @rtibbles

Reviewer guidance

  1. On a hybrid device or using device emulation, open the app and navigate to a Perseus exercise.
  2. Initially use touch input to interact with the app and observe Perseus rendering in mobile mode.
  3. Click anywhere in the app using the mouse or trackpad.
  4. Navigate to the same or a different Perseus exercise and verify that it now renders in standard mode, reflecting the detected mouse input.
  5. Attempt to switch back to touch input and observe that Perseus continues to render in standard mode, demonstrating the mouse input precedence.
Screen.Recording.2024-03-19.at.10.47.38.AM.mov

Testing checklist

  • Contributor has fully tested the PR manually
  • If there are any front-end changes, before/after screenshots are included
  • Critical user journeys are covered by Gherkin stories
  • Critical and brittle code paths are covered by unit tests

PR process

  • PR has the correct target branch and milestone
  • PR has 'needs review' or 'work-in-progress' label
  • If PR is ready for review, a reviewer has been added. (Don't use 'Assignees')
  • If this is an important user-facing change, PR or related issue has a 'changelog' label
  • If this includes an internal dependency change, a link to the diff is provided

Reviewer checklist

  • Automated test coverage is satisfactory
  • PR is fully functional
  • PR has been tested for accessibility regressions
  • External dependency files were updated if necessary (yarn and pip)
  • Documentation is updated
  • Contributor is in AUTHORS.md

@github-actions github-actions bot added DEV: renderers HTML5 apps, videos, exercises, etc. DEV: frontend SIZE: small labels Mar 19, 2024
@rtibbles rtibbles changed the base branch from develop to release-v0.16.x March 20, 2024 04:17
@rtibbles
Copy link
Member

Sorry @poju3185, I forgot to mention that we are targeting this fix to 0.16. I have retargeted the PR (please ignore the diff from that). Please follow the instructions here: https://kolibri-dev.readthedocs.io/en/develop/howtos/rebasing_a_pull_request.html
To rebase your pull request onto the release-v0.16.x branch.

@poju3185
Copy link
Contributor Author

No worries. I've already rebased the pull request onto the release-v0.16.x branch as instructed. Thank you for the guidance!

Copy link
Member

@rtibbles rtibbles left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This definitely works, but I think I'd rather make the API a bit more explicit and hide the implementation details from the API consumer.

@@ -58,6 +58,12 @@ export default class KolibriApp extends KolibriModule {
return {};
}

handlePointerDown(event) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I would rather move all of this logic into the browserInfo.js module - and create a simple exportable boolean in there mousePointerUsed or something like that.

This can be initialized from the localStorage initially, and then we can update both the localStorage and the value when the condition below happens.

@@ -110,6 +116,10 @@ export default class KolibriApp extends KolibriModule {
...this.stateSetters.map(setter => setter(this.store)),
]).then(() => {
this.startRootVue();
window.addEventListener('pointerdown', this.handlePointerDown.bind(this));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be done in the module level of browserInfo.js - it will only get executed once, so it feels safe to me.

In terms of unbinding, once we have detected this once, we don't need to be checking any more, so at that point we could remove the event listener.

@@ -144,7 +144,7 @@
return this.windowBreakpoint < 3;
},
usesTouch() {
return isTouchDevice;
return isTouchDevice && localStorage.getItem('mouseUsed') !== 'true';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I commented above, let's add a browserInfo exportable variable that will define this value - so that the implementation details are hidden from the code consumer here.

@rtibbles rtibbles self-assigned this Mar 21, 2024
Signed-off-by: PoJuDeSu <spes9850401@gmail.com>
Signed-off-by: PoJuDeSu <spes9850401@gmail.com>
@poju3185
Copy link
Contributor Author

I've made the updates, please notice that isMouseUsed is implemented as a function rather than a constant because its value may change over time.

Copy link
Member

@rtibbles rtibbles left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just one last thing to have a referent rather than a function for isMouseUsed.


window.addEventListener('pointerdown', handlePointerDown);

export function isMouseUsed() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One of the nice things about Javascript exports is that they are referential - this has the nice effect of being able to export dynamic variables from a module.

This means that we don't have to have isMouseUsed as a function, instead it can be initialized as:

export let isMouseUsed = localStorage.getItem('mouseUsed') === 'true';


function handlePointerDown(event) {
if (event.pointerType === 'mouse') {
localStorage.setItem('mouseUsed', 'true');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then in here we can do this and:

isMouseUsed = true;

Signed-off-by: PoJuDeSu <spes9850401@gmail.com>
@poju3185
Copy link
Contributor Author

poju3185 commented Mar 21, 2024

I've made the suggested change to initialize isMouseUsed using the export with the dynamic variable approach. Now the code looks better.

Copy link
Member

@rtibbles rtibbles left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good! I'll ask our QA team to give it a quick test if possible, just to make sure it's all working as intended.

@rtibbles rtibbles dismissed their stale review March 22, 2024 15:17

All addressed!

@pcenov
Copy link
Member

pcenov commented Mar 22, 2024

Hi @rtibbles - I've just tested this on a Chromebook laptop and I can confirm that I can input an answer both when using the touch screen or the trackpad. However when using only the touch screen I still have to type the answer using the physical keyboard of the device while I was expecting to see the onscreen numeric keyboard. The same is valid when I flip the physical keyboard of the Chromebook and start using it as a tablet in which case instead of seeing the onscreen numeric keyboard I see the normal digital keyboard.

@rtibbles
Copy link
Member

Thanks @pcenov - I think what you describe is sufficient to fix the issue at hand (being able to input at all in this scenario) but we can file a follow up issue for the behaviour that is more responsive to the current state of the device. This more responsive functionality will be significantly harder to implement.

@rtibbles
Copy link
Member

Follow up filed here: #12016

Copy link
Member

@rtibbles rtibbles left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work, thank you!

@rtibbles rtibbles merged commit b16c589 into learningequality:release-v0.16.x Mar 22, 2024
34 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
DEV: frontend DEV: renderers HTML5 apps, videos, exercises, etc. SIZE: small
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Keyboard input in perseus does not work with touchscreen devices
3 participants