Skip to content

Commit

Permalink
fix: dpad navigation improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
ThaUnknown committed Jun 29, 2024
1 parent 3dcf5ab commit 67407a5
Show file tree
Hide file tree
Showing 8 changed files with 86 additions and 16 deletions.
3 changes: 2 additions & 1 deletion common/css.css
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,8 @@ img[src=''], img[src=' '] {

*:focus-visible {
outline: none;
box-shadow: var(--dm-button-primary-box-shadow-focus) !important;
border-radius: 5px;
box-shadow: inset 0 0 0 1.5px #eee !important;
}

.modal:focus-visible {
Expand Down
2 changes: 0 additions & 2 deletions common/modules/anilist.js
Original file line number Diff line number Diff line change
Expand Up @@ -730,5 +730,3 @@ class AnilistClient {
}

export const anilistClient = new AnilistClient()

globalThis.alc = anilistClient
64 changes: 58 additions & 6 deletions common/modules/click.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ document.addEventListener('pointerup', () => {
})
})

/** @typedef {{element: Element, x: number, y: number, inViewport: boolean}} ElementPosition */

/**
* Adds click event listener to the specified node.
* @param {HTMLElement} node - The node to attach the click event listener to.
* @param {Function} [cb=noop] - The callback function to be executed on click.
*/
export function click (node, cb = noop) {
node.tabIndex = 0
node.role = 'button'
Expand All @@ -38,6 +45,11 @@ export function click (node, cb = noop) {
}
}

// TODO: this needs to be re-written.... again... it should detect pointer type and have separate functionality for mouse and touch and none for dpad
/**
* Adds hover and click event listeners to the specified node.
* @param {HTMLElement} node - The node to attach the event listeners to.
*/
export function hoverClick (node, [cb = noop, hoverUpdate = noop]) {
let pointerType = 'mouse'
node.tabIndex = 0
Expand Down Expand Up @@ -93,18 +105,30 @@ const Directions = { up: 1, right: 2, down: 3, left: 4 }
const InverseDirections = { up: 'down', down: 'up', left: 'right', right: 'left' }
const DirectionKeyMap = { ArrowDown: 'down', ArrowUp: 'up', ArrowLeft: 'left', ArrowRight: 'right' }

/**
* Calculates the direction between two points.
* @param {Object} anchor - The anchor point.
* @param {Object} relative - The relative point.
* @returns {number} - The direction between the two points.
*/
function getDirection (anchor, relative) {
return Math.round((Math.atan2(relative.y - anchor.y, relative.x - anchor.x) * 180 / Math.PI + 180) / 90)
}

/**
* Calculates the distance between two points.
* @param {Object} anchor - The anchor point.
* @param {Object} relative - The relative point.
* @returns {number} - The distance between the two points.
*/
function getDistance (anchor, relative) {
return Math.hypot(relative.x - anchor.x, relative.y - anchor.y)
}

/**
* Gets keyboard-focusable elements within a specified element
* @param {Element} [element=document.body] element
* @returns {Element[]}
* Gets keyboard-focusable elements within a specified element.
* @param {Element} [element=document.body] - The element to search within.
* @returns {Element[]} - An array of keyboard-focusable elements.
*/
function getKeyboardFocusableElements (element = document.body) {
return [...element.querySelectorAll('a[href], button:not([disabled]), fieldset:not([disabled]), input:not([disabled]), optgroup:not([disabled]), option:not([disabled]), select:not([disabled]), textarea:not([disabled]), details, [tabindex]:not([tabindex="-1"]), [contenteditable], [controls]')].filter(
Expand All @@ -113,14 +137,20 @@ function getKeyboardFocusableElements (element = document.body) {
}

/**
* @param {Element} element
* Gets the position of an element.
* @param {Element} element - The element to get the position of.
* @returns {ElementPosition} - The position of the element.
*/
function getElementPosition (element) {
const { x, y, width, height, top, left, bottom, right } = element.getBoundingClientRect()
const inViewport = isInViewport({ top, left, bottom, right })
return { element, x: x + width * 0.5, y: y + height * 0.5, inViewport }
}

/**
* Gets the positions of all focusable elements.
* @returns {ElementPosition[]} - An array of element positions.
*/
function getFocusableElementPositions () {
const elements = []
for (const element of getKeyboardFocusableElements(document.querySelector('.modal.show') ?? document.body)) {
Expand All @@ -130,6 +160,11 @@ function getFocusableElementPositions () {
return elements
}

/**
* Checks if an element is within the viewport.
* @param {Object} rect - The coordinates of the element.
* @returns {boolean} - True if the element is within the viewport, false otherwise.
*/
function isInViewport ({ top, left, bottom, right }) {
return top >= 0 && left >= 0 && bottom <= window.innerHeight && right <= window.innerWidth
}
Expand All @@ -141,6 +176,12 @@ function isInViewport ({ top, left, bottom, right }) {
// return false
// }

/**
* @param {ElementPosition[]} keyboardFocusable
* @param {ElementPosition} currentElement
* @param {string} direction
* @returns {ElementPosition[]}
*/
function getElementsInDesiredDirection (keyboardFocusable, currentElement, direction) {
// first try finding visible elements in desired direction
return keyboardFocusable.filter(position => {
Expand All @@ -154,6 +195,10 @@ function getElementsInDesiredDirection (keyboardFocusable, currentElement, direc
})
}

/**
* Navigates using D-pad keys.
* @param {string} [direction='up'] - The direction to navigate.
*/
function navigateDPad (direction = 'up') {
const keyboardFocusable = getFocusableElementPositions()
const currentElement = !document.activeElement || document.activeElement === document.body ? keyboardFocusable[0] : getElementPosition(document.activeElement)
Expand All @@ -168,8 +213,15 @@ function navigateDPad (direction = 'up') {
return reducer
}, { distance: Infinity, element: null })

closestElement.element.focus()
closestElement.element.scrollIntoView({ block: 'center', inline: 'nearest', behavior: 'smooth' })
/** @type {{element: HTMLElement}} */
const { element } = closestElement

const isInput = element.matches('input[type=text], input[type=url], input[type=number], textarea')
// make readonly
if (isInput) element.readOnly = true
element.focus()
if (isInput) setTimeout(() => { element.readOnly = false })
element.scrollIntoView({ block: 'center', inline: 'nearest', behavior: 'smooth' })
return
}

Expand Down
4 changes: 2 additions & 2 deletions common/modules/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,9 @@ export const defaults = {
doHURL: 'https://cloudflare-dns.com/dns-query',
disableSubtitleBlur: SUPPORTS.isAndroid,
showDetailsInRPC: true,
smoothScroll: true,
smoothScroll: !SUPPORTS.isAndroid,
cards: 'small',
expandingSidebar: true,
expandingSidebar: !SUPPORTS.isAndroid,
torrentPathNew: undefined,
font: undefined,
angle: 'default',
Expand Down
21 changes: 20 additions & 1 deletion common/views/Player/Player.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -985,6 +985,25 @@
break
}
}
function handleSeekbarKey (e) {
if (e.key === 'ArrowLeft') {
e.stopPropagation()
e.stopImmediatePropagation()
e.preventDefault()
rewind()
} else if (e.key === 'ArrowRight') {
e.stopPropagation()
e.stopImmediatePropagation()
e.preventDefault()
forward()
} else if (e.key === 'ArrowDown') {
e.stopPropagation()
e.stopImmediatePropagation()
e.preventDefault()
document.querySelector('div[data-name=\'toggleFullscreen\']')?.focus()
}
}
</script>
<!-- <svelte:window bind:innerWidth bind:innerHeight /> -->
Expand Down Expand Up @@ -1101,7 +1120,7 @@
{/if}
</div>
<div class='bottom d-flex z-40 flex-column px-20'>
<div class='w-full d-flex align-items-center h-20 mb-5 seekbar' tabindex='0' role='button'>
<div class='w-full d-flex align-items-center h-20 mb-5 seekbar' tabindex='0' role='button' on:keydown={handleSeekbarKey}>
<Seekbar
accentColor='var(--accent-color)'
class='font-size-20'
Expand Down
2 changes: 1 addition & 1 deletion common/views/Settings/Settings.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@
{:then changelog}
{#each changelog as { version, date, body }}
<hr class='my-20' />
<div class='row py-20 px-20 px-sm-0 position-relative'>
<div class='row py-20 px-20 px-sm-0 position-relative' tabindex='0' role='button'>
<div class='col-sm-3 order-last order-sm-first text-white'>
<div class='position-sticky top-0 pt-20'>
{new Date(date).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })}
Expand Down
4 changes: 2 additions & 2 deletions common/views/ViewAnime/EpisodeList.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@
{@const completed = !watched && userProgress >= episode}
{@const target = userProgress + 1 === episode}
{@const progress = !watched && ($animeProgress?.[episode] ?? 0)}
<div class='w-full my-20 content-visibility-auto scale' class:opacity-half={completed} class:px-20={!target} class:h-150={image || summary} use:click={() => play(episode)}>
<div class='rounded w-full h-full overflow-hidden d-flex flex-xsm-column flex-row pointer' class:border={target} class:bg-black={completed} class:bg-dark={!completed}>
<div class='w-full my-20 content-visibility-auto scale' class:opacity-half={completed} class:px-20={!target} class:h-150={image || summary}>
<div class='rounded w-full h-full overflow-hidden d-flex flex-xsm-column flex-row pointer' class:border={target} class:bg-black={completed} class:bg-dark={!completed} use:click={() => play(episode)}>
{#if image}
<div class='h-full'>
<img alt='thumbnail' src={image} class='img-cover h-full' />
Expand Down
2 changes: 1 addition & 1 deletion electron/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "Miru",
"version": "5.1.6",
"version": "5.1.7",
"private": true,
"author": "ThaUnknown_ <[email protected]>",
"description": "Stream anime torrents, real-time with no waiting for downloads.",
Expand Down

0 comments on commit 67407a5

Please sign in to comment.