From 2d2efe3dcfe98c0410277a2b7da316f7a968609d Mon Sep 17 00:00:00 2001 From: austinried <4966622+austinried@users.noreply.github.com> Date: Tue, 10 Aug 2021 15:27:20 +0900 Subject: [PATCH] added seeking to now playing/notification --- app/components/NowPlayingBar.tsx | 6 +-- app/hooks/trackplayer.ts | 7 ++++ app/playbackservice.ts | 6 +++ app/screens/NowPlayingView.tsx | 72 +++++++++++++++++++++++++------- index.js | 1 + package.json | 1 + yarn.lock | 5 +++ 7 files changed, 78 insertions(+), 20 deletions(-) diff --git a/app/components/NowPlayingBar.tsx b/app/components/NowPlayingBar.tsx index 8c165bd..4f2fa60 100644 --- a/app/components/NowPlayingBar.tsx +++ b/app/components/NowPlayingBar.tsx @@ -21,8 +21,8 @@ const ProgressBar = () => { return ( - - + + ) } @@ -52,8 +52,6 @@ const NowPlayingBar = () => { switch (playerState) { case State.Playing: - case State.Buffering: - case State.Connecting: playPauseIcon = 'pause' playPauseAction = pause break diff --git a/app/hooks/trackplayer.ts b/app/hooks/trackplayer.ts index face3fe..63a3ce0 100644 --- a/app/hooks/trackplayer.ts +++ b/app/hooks/trackplayer.ts @@ -60,6 +60,13 @@ export const useSkipTo = () => { }) } +export const useSeekTo = () => { + return (position: number) => + trackPlayerCommands.enqueue(async () => { + await TrackPlayer.seekTo(position) + }) +} + export const useToggleRepeat = () => { const setRepeatMode = useStore(selectTrackPlayer.setRepeatMode) diff --git a/app/playbackservice.ts b/app/playbackservice.ts index a4c9b7a..53d9cea 100644 --- a/app/playbackservice.ts +++ b/app/playbackservice.ts @@ -82,6 +82,12 @@ const createService = async () => { TrackPlayer.addEventListener(Event.PlaybackMetadataReceived, () => { setCurrentTrackIdx(useStore.getState().currentTrackIdx) }) + + TrackPlayer.addEventListener(Event.RemoteSeek, data => { + trackPlayerCommands.enqueue(async () => { + await TrackPlayer.seekTo(data.position) + }) + }) } module.exports = async function () { diff --git a/app/screens/NowPlayingView.tsx b/app/screens/NowPlayingView.tsx index 1c311b3..3d76a2e 100644 --- a/app/screens/NowPlayingView.tsx +++ b/app/screens/NowPlayingView.tsx @@ -3,7 +3,15 @@ import ImageGradientBackground from '@app/components/ImageGradientBackground' import PressableOpacity from '@app/components/PressableOpacity' import Star from '@app/components/Star' import { useStarred } from '@app/hooks/music' -import { useNext, usePause, usePlay, usePrevious, useToggleRepeat, useToggleShuffle } from '@app/hooks/trackplayer' +import { + useNext, + usePause, + usePlay, + usePrevious, + useSeekTo, + useToggleRepeat, + useToggleShuffle, +} from '@app/hooks/trackplayer' import { selectMusic } from '@app/state/music' import { useStore } from '@app/state/store' import { QueueContextType, selectTrackPlayer } from '@app/state/trackplayer' @@ -12,7 +20,7 @@ import dimensions from '@app/styles/dimensions' import font from '@app/styles/font' import formatDuration from '@app/util/formatDuration' import { useNavigation } from '@react-navigation/native' -import React, { useCallback, useEffect } from 'react' +import React, { useCallback, useEffect, useState } from 'react' import { StatusBar, StyleSheet, Text, View } from 'react-native' import { NativeStackScreenProps } from 'react-native-screens/native-stack' import { RepeatMode, State } from 'react-native-track-player' @@ -21,6 +29,7 @@ import IconFA5 from 'react-native-vector-icons/FontAwesome5' import Icon from 'react-native-vector-icons/Ionicons' import IconMatCom from 'react-native-vector-icons/MaterialCommunityIcons' import IconMat from 'react-native-vector-icons/MaterialIcons' +import Slider from '@react-native-community/slider' function getContextName(type?: QueueContextType) { switch (type) { @@ -131,7 +140,8 @@ const coverArtStyles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', - paddingBottom: 20, + paddingBottom: 10, + paddingHorizontal: 10, }, image: { height: '100%', @@ -169,6 +179,7 @@ const infoStyles = StyleSheet.create({ container: { width: '100%', flexDirection: 'row', + paddingHorizontal: 10, }, details: { flex: 1, @@ -193,21 +204,46 @@ const infoStyles = StyleSheet.create({ const SeekBar = () => { const { position, duration } = useStore(selectTrackPlayer.progress) + const seekTo = useSeekTo() + const [value, setValue] = useState(0) + const [sliding, setSliding] = useState(false) - let progress = 0 - if (duration > 0) { - progress = position / duration - } + useEffect(() => { + if (sliding) { + return + } + + setValue(position) + }, [position, sliding]) + + const onSlidingStart = useCallback(() => { + setSliding(true) + }, []) + + const onSlidingComplete = useCallback( + async (val: number) => { + await seekTo(val) + setSliding(false) + }, + [seekTo], + ) return ( - - - + - {formatDuration(position)} + {formatDuration(value)} {formatDuration(duration)} @@ -217,17 +253,21 @@ const SeekBar = () => { const seekStyles = StyleSheet.create({ container: { width: '100%', - marginTop: 26, + marginTop: 16, }, barContainer: { flexDirection: 'row', alignItems: 'center', - marginBottom: 6, + marginBottom: 0, }, bars: { backgroundColor: colors.text.primary, height: 4, }, + slider: { + flex: 1, + height: 40, + }, barLeft: { marginRight: -6, }, @@ -245,6 +285,7 @@ const seekStyles = StyleSheet.create({ textContainer: { flexDirection: 'row', justifyContent: 'space-between', + paddingHorizontal: 10, }, text: { fontFamily: font.regular, @@ -271,8 +312,6 @@ const PlayerControls = () => { switch (state) { case State.Playing: - case State.Buffering: - case State.Connecting: disabled = false playPauseIcon = 'pause-circle' playPauseAction = pause @@ -327,6 +366,7 @@ const PlayerControls = () => { const controlsStyles = StyleSheet.create({ container: { width: '100%', + paddingHorizontal: 10, }, top: { flexDirection: 'row', @@ -395,7 +435,7 @@ const styles = StyleSheet.create({ }, content: { flex: 1, - paddingHorizontal: 30, + paddingHorizontal: 20, }, }) diff --git a/index.js b/index.js index caa0bf8..e54027b 100644 --- a/index.js +++ b/index.js @@ -24,6 +24,7 @@ async function start() { Capability.Stop, Capability.SkipToNext, Capability.SkipToPrevious, + Capability.SeekTo, ], compactCapabilities: [ Capability.Play, // diff --git a/package.json b/package.json index 02d01c6..600487e 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "@react-native-async-storage/async-storage": "^1.15.5", "@react-native-community/hooks": "^2.6.0", "@react-native-community/masked-view": "^0.1.11", + "@react-native-community/slider": "^3.0.3", "@react-navigation/bottom-tabs": "^5.11.11", "@react-navigation/material-top-tabs": "^5.3.15", "@react-navigation/native": "^5.9.4", diff --git a/yarn.lock b/yarn.lock index 2ee33cc..ca0a54f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1118,6 +1118,11 @@ resolved "https://registry.yarnpkg.com/@react-native-community/masked-view/-/masked-view-0.1.11.tgz#2f4c6e10bee0786abff4604e39a37ded6f3980ce" integrity sha512-rQfMIGSR/1r/SyN87+VD8xHHzDYeHaJq6elOSCAD+0iLagXkSI2pfA0LmSXP21uw5i3em7GkkRjfJ8wpqWXZNw== +"@react-native-community/slider@^3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@react-native-community/slider/-/slider-3.0.3.tgz#830167fd757ba70ac638747ba3169b2dbae60330" + integrity sha512-8IeHfDwJ9/CTUwFs6x90VlobV3BfuPgNLjTgC6dRZovfCWigaZwVNIFFJnHBakK3pW2xErAPwhdvNR4JeNoYbw== + "@react-native/assets@1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@react-native/assets/-/assets-1.0.0.tgz#c6f9bf63d274bafc8e970628de24986b30a55c8e"