mirror of
https://github.com/Andre-Bzk/twitch4steamdeck.git
synced 2026-11-15 15:43:08 +01:00
Phase 6 Fix 4
- Unter "Du folgst" wurde immer der erste Kanal aufgerufen, unabhängig vom ausgewählten Kanal - Abbrechen der Wiedergabe auch unter "Durchsuchen" und Top-Stream möglich.
This commit is contained in:
@@ -23,6 +23,8 @@ const BUTTON_MAP: Record<number, string> = {
|
||||
1: 'Escape', // B
|
||||
2: 'x', // X
|
||||
3: 'y', // Y
|
||||
6: 'l2', // LT / L2
|
||||
7: 'r2', // RT / R2
|
||||
12: 'ArrowUp',
|
||||
13: 'ArrowDown',
|
||||
14: 'ArrowLeft',
|
||||
|
||||
@@ -107,6 +107,15 @@ export default function BrowseScreen({
|
||||
if (!hasFocus) return
|
||||
|
||||
const onKey = (e: KeyboardEvent): void => {
|
||||
// Während der Wiedergabe: nur Stop erlauben, Navigation blockieren
|
||||
if (isPlaying) {
|
||||
e.preventDefault()
|
||||
if (e.key === 'Escape' || e.key === 'Enter' || e.key === ' ') {
|
||||
void window.t4sd.playback.stop()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (e.key === 'y' || e.key === 'Y') {
|
||||
void load()
|
||||
return
|
||||
@@ -145,12 +154,10 @@ export default function BrowseScreen({
|
||||
if (ch) onSelectChannel(ch)
|
||||
break
|
||||
}
|
||||
case 'Escape': {
|
||||
case 'Escape':
|
||||
e.preventDefault()
|
||||
if (isPlaying) void window.t4sd.playback.stop()
|
||||
else onRequestSidebar()
|
||||
onRequestSidebar()
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// grid region
|
||||
@@ -184,12 +191,10 @@ export default function BrowseScreen({
|
||||
if (game) onSelectCategory(game)
|
||||
break
|
||||
}
|
||||
case 'Escape': {
|
||||
case 'Escape':
|
||||
e.preventDefault()
|
||||
if (isPlaying) void window.t4sd.playback.stop()
|
||||
else onRequestSidebar()
|
||||
onRequestSidebar()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ export default function CategoryScreen({ game, onSelectChannel, onBack }: Props)
|
||||
const [streams, setStreams] = useState<FollowedChannelInfo[]>([])
|
||||
const [loadState, setLoadState] = useState<LoadState>('loading')
|
||||
const [focusedIndex, setFocusedIndex] = useState(0)
|
||||
const [isPlaying, setIsPlaying] = useState(false)
|
||||
const gridRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
const load = useCallback(async () => {
|
||||
@@ -33,6 +34,13 @@ export default function CategoryScreen({ game, onSelectChannel, onBack }: Props)
|
||||
void load()
|
||||
}, [load])
|
||||
|
||||
useEffect(() => {
|
||||
return window.t4sd.playback.onEvent((ev) => {
|
||||
if (ev.kind === 'started') setIsPlaying(true)
|
||||
else if (ev.kind === 'stopped' || ev.kind === 'error') setIsPlaying(false)
|
||||
})
|
||||
}, [])
|
||||
|
||||
const getColumns = useCallback((): number => {
|
||||
const grid = gridRef.current
|
||||
if (!grid) return 4
|
||||
@@ -42,6 +50,15 @@ export default function CategoryScreen({ game, onSelectChannel, onBack }: Props)
|
||||
|
||||
useEffect(() => {
|
||||
const onKey = (e: KeyboardEvent): void => {
|
||||
// Während der Wiedergabe: nur Stop erlauben, Navigation blockieren
|
||||
if (isPlaying) {
|
||||
e.preventDefault()
|
||||
if (e.key === 'Escape' || e.key === 'Enter' || e.key === ' ') {
|
||||
void window.t4sd.playback.stop()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (e.key === 'y' || e.key === 'Y') {
|
||||
void load()
|
||||
return
|
||||
@@ -94,7 +111,7 @@ export default function CategoryScreen({ game, onSelectChannel, onBack }: Props)
|
||||
|
||||
window.addEventListener('keydown', onKey)
|
||||
return () => window.removeEventListener('keydown', onKey)
|
||||
}, [loadState, streams, focusedIndex, getColumns, onBack, onSelectChannel, load])
|
||||
}, [loadState, streams, focusedIndex, isPlaying, getColumns, onBack, onSelectChannel, load])
|
||||
|
||||
return (
|
||||
<div className="category-screen">
|
||||
|
||||
@@ -73,6 +73,39 @@ export default function ChannelScreen({ channel, onBack }: Props): JSX.Element {
|
||||
|
||||
useEffect(() => {
|
||||
const onKey = (e: KeyboardEvent): void => {
|
||||
const isPlaying = playState === 'playing' || playState === 'starting'
|
||||
|
||||
// Während der Wiedergabe: nur Playback-Steuerung erlauben, keine Navigation
|
||||
if (isPlaying) {
|
||||
switch (e.key) {
|
||||
case 'l2':
|
||||
e.preventDefault()
|
||||
void window.t4sd.playback.seek(-300)
|
||||
break
|
||||
case 'r2':
|
||||
e.preventDefault()
|
||||
void window.t4sd.playback.seek(300)
|
||||
break
|
||||
case 'ArrowLeft':
|
||||
e.preventDefault()
|
||||
void window.t4sd.playback.seek(-30)
|
||||
break
|
||||
case 'ArrowRight':
|
||||
e.preventDefault()
|
||||
void window.t4sd.playback.seek(30)
|
||||
break
|
||||
case 'Enter':
|
||||
case ' ':
|
||||
case 'Escape':
|
||||
e.preventDefault()
|
||||
void window.t4sd.playback.stop()
|
||||
break
|
||||
default:
|
||||
e.preventDefault() // alle anderen Tasten blockieren
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (focusRegion === 'hero') {
|
||||
if (e.key === 'ArrowDown' && vods.length > 0) {
|
||||
e.preventDefault()
|
||||
@@ -80,18 +113,12 @@ export default function ChannelScreen({ channel, onBack }: Props): JSX.Element {
|
||||
setShelfIndex(0)
|
||||
} else if (e.key === 'Enter' || e.key === ' ') {
|
||||
e.preventDefault()
|
||||
if (playState === 'playing' || playState === 'starting') {
|
||||
void window.t4sd.playback.stop()
|
||||
} else if (channel.isLive) {
|
||||
if (channel.isLive) {
|
||||
void handleWatch()
|
||||
}
|
||||
} else if (e.key === 'Escape') {
|
||||
e.preventDefault()
|
||||
if (playState === 'playing' || playState === 'starting') {
|
||||
void window.t4sd.playback.stop()
|
||||
} else {
|
||||
onBack()
|
||||
}
|
||||
onBack()
|
||||
}
|
||||
} else {
|
||||
// shelf region
|
||||
@@ -111,11 +138,7 @@ export default function ChannelScreen({ channel, onBack }: Props): JSX.Element {
|
||||
if (vod) void handleWatchVod(vod)
|
||||
} else if (e.key === 'Escape') {
|
||||
e.preventDefault()
|
||||
if (playState === 'playing' || playState === 'starting') {
|
||||
void window.t4sd.playback.stop()
|
||||
} else {
|
||||
onBack()
|
||||
}
|
||||
onBack()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -252,7 +275,7 @@ export default function ChannelScreen({ channel, onBack }: Props): JSX.Element {
|
||||
|
||||
{playState === 'playing' && (
|
||||
<>
|
||||
<span className="channel-screen__playing-hint">● Wiedergabe läuft in mpv</span>
|
||||
<span className="channel-screen__playing-hint">● Wiedergabe läuft in mpv · ← −30s · → +30s · LT −5min · RT +5min</span>
|
||||
<button className="btn" onClick={() => void handleStop()}>
|
||||
■ Stop (B / Escape)
|
||||
</button>
|
||||
|
||||
Vendored
+1
@@ -81,6 +81,7 @@ export interface T4sdApi {
|
||||
startLive: (channelLogin: string, quality?: string) => Promise<void>
|
||||
startVod: (vodId: string, channelLogin: string, title: string, durationSeconds: number) => Promise<void>
|
||||
stop: () => Promise<void>
|
||||
seek: (seconds: number) => Promise<void>
|
||||
onEvent: (cb: (event: PlaybackEvent) => void) => () => void
|
||||
}
|
||||
gamepad: {
|
||||
|
||||
Reference in New Issue
Block a user