mirror of
https://github.com/NoCrypt/migu.git
synced 2026-04-18 23:22:05 +00:00
fix: TMP path on android, keybinds on android, not immersed when paused
feat: greatly improve dpad navigation fix: #386
This commit is contained in:
parent
1a309d74f9
commit
ee480d992b
8 changed files with 90 additions and 30 deletions
|
|
@ -1,5 +1,6 @@
|
|||
import TorrentClient from 'common/modules/webtorrent.js'
|
||||
import { channel } from 'bridge'
|
||||
import { env } from 'node:process'
|
||||
import { statfs } from 'fs/promises'
|
||||
|
||||
async function storageQuota (directory) {
|
||||
|
|
@ -30,4 +31,4 @@ channel.on('port-init', data => {
|
|||
}))
|
||||
})
|
||||
|
||||
globalThis.client = new TorrentClient(channel, storageQuota, 'node')
|
||||
globalThis.client = new TorrentClient(channel, storageQuota, 'node', { torrentPath: env.TMPDIR })
|
||||
|
|
|
|||
|
|
@ -9,5 +9,6 @@ export const SUPPORTS = {
|
|||
discord: false,
|
||||
torrentPort: true,
|
||||
torrentPath: false,
|
||||
torrentPersist: true
|
||||
torrentPersist: false,
|
||||
keybinds: false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,12 @@ export function click (node, cb = noop) {
|
|||
node.addEventListener('pointerleave', e => {
|
||||
e.stopPropagation()
|
||||
})
|
||||
node.addEventListener('keydown', e => { if (e.key === 'Enter') cb(e) })
|
||||
node.addEventListener('keydown', e => {
|
||||
if (e.key === 'Enter') {
|
||||
e.stopPropagation()
|
||||
cb(e)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function hoverClick (node, [cb = noop, hoverUpdate = noop]) {
|
||||
|
|
@ -52,6 +57,7 @@ export function hoverClick (node, [cb = noop, hoverUpdate = noop]) {
|
|||
})
|
||||
node.addEventListener('keydown', e => {
|
||||
if (e.key === 'Enter') {
|
||||
e.stopPropagation()
|
||||
lastTapElement?.(false)
|
||||
if (lastTapElement === hoverUpdate) {
|
||||
lastTapElement = null
|
||||
|
|
@ -73,6 +79,8 @@ export function hoverClick (node, [cb = noop, hoverUpdate = noop]) {
|
|||
}
|
||||
|
||||
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' }
|
||||
|
||||
function getDirection (anchor, relative) {
|
||||
return Math.round((Math.atan2(relative.y - anchor.y, relative.x - anchor.x) * 180 / Math.PI + 180) / 90)
|
||||
|
|
@ -97,9 +105,10 @@ function getKeyboardFocusableElements (element = document.body) {
|
|||
* @param {Element} element
|
||||
*/
|
||||
function getElementPosition (element) {
|
||||
const { x, y, width, height } = element.getBoundingClientRect()
|
||||
const { x, y, width, height, top, left, bottom, right } = element.getBoundingClientRect()
|
||||
const inViewport = isInViewport({ top, left, bottom, right })
|
||||
if (width || height) {
|
||||
return { element, x: x + width * 0.5, y: y + height * 0.5 }
|
||||
return { element, x: x + width * 0.5, y: y + height * 0.5, inViewport }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -112,30 +121,67 @@ function getFocusableElementPositions () {
|
|||
return elements
|
||||
}
|
||||
|
||||
function isInViewport ({ top, left, bottom, right }) {
|
||||
return (
|
||||
top >= 0 &&
|
||||
left >= 0 &&
|
||||
bottom <= window.innerHeight &&
|
||||
right <= window.innerWidth
|
||||
)
|
||||
}
|
||||
|
||||
// function isVisible ({ top, left, bottom, right }, element) {
|
||||
// for (const [x, y] of [[left, top], [right, top], [left, bottom], [right, bottom]]) {
|
||||
// if (document.elementFromPoint(x, y)?.isSameNode(element)) return true
|
||||
// }
|
||||
// return false
|
||||
// }
|
||||
|
||||
function getElementsInDesiredDirection (keyboardFocusable, currentElement, direction) {
|
||||
// first try finding visible elements in desired direction
|
||||
return keyboardFocusable.filter(position => {
|
||||
// in order of computation cost
|
||||
if (position.element === currentElement.element) return false
|
||||
if (getDirection(currentElement, position) !== Directions[direction]) return false
|
||||
|
||||
// filters out elements which are in the viewport, but are overlayed by other elements like a modal
|
||||
if (position.inViewport && !position.element.checkVisibility()) return false
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
function navigateDPad (direction = 'up') {
|
||||
const keyboardFocusable = getFocusableElementPositions()
|
||||
const currentElement = !document.activeElement || document.activeElement === document.body ? keyboardFocusable[0] : getElementPosition(document.activeElement)
|
||||
|
||||
const elementsInDesiredDirection = keyboardFocusable.filter(position => {
|
||||
return position.element !== currentElement.element && getDirection(currentElement, position) === Directions[direction]
|
||||
})
|
||||
const elementsInDesiredDirection = getElementsInDesiredDirection(keyboardFocusable, currentElement, direction)
|
||||
|
||||
const closestElement = elementsInDesiredDirection.reduce((reducer, position) => {
|
||||
const distance = getDistance(currentElement, position)
|
||||
if (distance < reducer.distance) return { distance, element: position.element }
|
||||
return reducer
|
||||
}, { distance: Infinity, element: null })
|
||||
// if there are elements in desired direction
|
||||
if (elementsInDesiredDirection.length) {
|
||||
const closestElement = elementsInDesiredDirection.reduce((reducer, position) => {
|
||||
const distance = getDistance(currentElement, position)
|
||||
if (distance < reducer.distance) return { distance, element: position.element }
|
||||
return reducer
|
||||
}, { distance: Infinity, element: null })
|
||||
|
||||
closestElement.element.focus()
|
||||
}
|
||||
const keyMap = {
|
||||
ArrowDown: 'down',
|
||||
ArrowUp: 'up',
|
||||
ArrowLeft: 'left',
|
||||
ArrowRight: 'right'
|
||||
closestElement.element.focus()
|
||||
return
|
||||
}
|
||||
|
||||
// no elements in desired direction, go to opposite end [wrap around]
|
||||
const elementsInOppositeDirection = getElementsInDesiredDirection(keyboardFocusable, currentElement, InverseDirections[direction])
|
||||
if (elementsInOppositeDirection.length) {
|
||||
const furthestElement = elementsInOppositeDirection.reduce((reducer, position) => {
|
||||
const distance = getDistance(currentElement, position)
|
||||
if (distance > reducer.distance) return { distance, element: position.element }
|
||||
return reducer
|
||||
}, { distance: -Infinity, element: null })
|
||||
|
||||
furthestElement.element.focus()
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('keydown', e => {
|
||||
e.preventDefault()
|
||||
navigateDPad(keyMap[e.key])
|
||||
if (DirectionKeyMap[e.key]) navigateDPad(DirectionKeyMap[e.key])
|
||||
})
|
||||
|
|
|
|||
|
|
@ -9,5 +9,6 @@ export const SUPPORTS = {
|
|||
discord: true,
|
||||
torrentPort: true,
|
||||
torrentPath: true,
|
||||
torrentPersist: true
|
||||
torrentPersist: true,
|
||||
keybinds: true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
import { w2gEmitter, state } from '../WatchTogether/WatchTogether.svelte'
|
||||
import Keybinds, { loadWithDefaults, condition } from 'svelte-keybinds'
|
||||
import { SUPPORTS } from '@/modules/support.js'
|
||||
|
||||
const emit = createEventDispatcher()
|
||||
|
||||
|
|
@ -38,7 +39,7 @@
|
|||
}
|
||||
|
||||
export let miniplayer = false
|
||||
$condition = () => !miniplayer
|
||||
$condition = () => !miniplayer && SUPPORTS.keybinds
|
||||
export let page
|
||||
export let files = []
|
||||
$: updateFiles(files)
|
||||
|
|
@ -869,7 +870,7 @@
|
|||
}
|
||||
break
|
||||
default:
|
||||
console.warn('An unknown error occurred.')
|
||||
console.warn('An unknown video playback error occurred.')
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
@ -881,13 +882,14 @@
|
|||
class:pointer={miniplayer}
|
||||
class:miniplayer
|
||||
class:pip
|
||||
class:immersed
|
||||
class:immersed={immersed && !paused}
|
||||
class:buffering={src && buffering}
|
||||
bind:this={container}
|
||||
role='none'
|
||||
on:mousemove={resetImmerse}
|
||||
on:touchmove={resetImmerse}
|
||||
on:keypress={resetImmerse}
|
||||
on:keydown={resetImmerse}
|
||||
on:mouseleave={immersePlayer}>
|
||||
{#if showKeybinds && !miniplayer}
|
||||
<div class='position-absolute bg-tp w-full h-full z-50 font-size-12 p-20 d-flex align-items-center justify-content-center pointer' on:pointerup|self={() => (showKeybinds = false)} tabindex='-1' role='button'>
|
||||
|
|
@ -983,7 +985,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'>
|
||||
<div class='w-full d-flex align-items-center h-20 mb-5 seekbar' tabindex='0' role='button'>
|
||||
<Seekbar
|
||||
accentColor='var(--accent-color)'
|
||||
class='font-size-20'
|
||||
|
|
@ -1082,7 +1084,7 @@
|
|||
object-fit: cover;
|
||||
}
|
||||
.custom-range {
|
||||
color: #e5204c;
|
||||
color: var(--accent-color);
|
||||
--thumb-height: 0px;
|
||||
--track-height: 3px;
|
||||
--track-color: rgba(255, 255, 255, 0.2);
|
||||
|
|
@ -1350,6 +1352,12 @@
|
|||
transition: width 0.1s ease;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@media (pointer: none), (pointer: coarse) {
|
||||
.bottom .volume .custom-range {
|
||||
width: 5vw;
|
||||
}
|
||||
}
|
||||
.h-20 {
|
||||
height: 2rem
|
||||
}
|
||||
|
|
@ -1371,8 +1379,7 @@
|
|||
@media (pointer: none), (pointer: coarse) {
|
||||
.bottom .ctrl[data-name='playPause'],
|
||||
.bottom .ctrl[data-name='playNext'],
|
||||
.bottom .volume,
|
||||
.bottom .ctrl[data-name='toggleFullscreen'] {
|
||||
.bottom .volume {
|
||||
display: none;
|
||||
}
|
||||
@media (orientation: portrait) {
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@
|
|||
<div class='row px-20'>
|
||||
<div class='col-lg-7 col-12 pb-10'>
|
||||
<div class='d-flex flex-sm-row flex-column align-items-sm-end pb-20 mb-15'>
|
||||
<div class='cover d-flex flex-row align-items-sm-end align-items-center justify-content-center mw-full mb-sm-0 mb-20' style='max-height: 50vh;'>
|
||||
<div class='cover d-flex flex-row align-items-sm-end align-items-center justify-content-center mw-full mb-sm-0 mb-20 w-full' style='max-height: 50vh;'>
|
||||
<img class='rounded cover-img overflow-hidden h-full' alt='cover-art' src={media.coverImage?.extraLarge || media.coverImage?.medium} />
|
||||
</div>
|
||||
<div class='pl-sm-20 ml-sm-20'>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// this is a bit scuffed, but these are cf pages redirect functions
|
||||
|
||||
/** @type {PagesFunction} */
|
||||
export function onRequest ({ params }) {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// this is a bit scuffed, but these are cf pages redirect functions
|
||||
|
||||
/** @type {PagesFunction} */
|
||||
export function onRequest ({ params }) {
|
||||
try {
|
||||
|
|
|
|||
Loading…
Reference in a new issue