@@ -12,10 +12,12 @@ import {
1212 Text ,
1313 TouchableOpacity ,
1414 StyleSheet ,
15+ Image ,
1516} from 'react-native' ;
1617import TrackPlayer , { State , usePlaybackState , useProgress } from 'react-native-track-player' ;
1718import { useTTSStore , useThemeStore } from '../stores' ;
1819import { getTheme , spacing , fontSizes , borderRadius } from '../utils/theme' ;
20+ import { getCoverImageUrl } from '../services/api' ;
1921import type { RootStackParamList } from '../navigation/types' ;
2022
2123export function TTSMiniPlayer ( ) {
@@ -27,8 +29,13 @@ export function TTSMiniPlayer() {
2729 const playbackState = usePlaybackState ( ) ;
2830 const progress = useProgress ( ) ;
2931
30- const isPlaying = playbackState . state === State . Playing ;
31- const isPaused = playbackState . state === State . Paused ;
32+ const isPlaying = ttsStore . state === 'playing' ;
33+ const isPaused = ttsStore . state === 'paused' ;
34+
35+ const paragraphProgress = progress . duration > 0 ? progress . position / progress . duration : 0 ;
36+ const overallProgress = ttsStore . totalParagraphs > 0
37+ ? ( ttsStore . currentParagraph + paragraphProgress ) / ttsStore . totalParagraphs
38+ : 0 ;
3239
3340 const styles = useMemo ( ( ) => createStyles ( theme ) , [ theme ] ) ;
3441
@@ -43,18 +50,16 @@ export function TTSMiniPlayer() {
4350 } , [ isPaused , isPlaying , ttsStore ] ) ;
4451
4552 const handleExpand = useCallback ( ( ) => {
46- // Navigate back to TTSScreen
47- if ( ttsStore . currentBookId ) {
48- // We need the book object to navigate - this is a limitation
49- // In practice, the mini player should be shown only when
50- // the TTSScreen is in the navigation stack
53+ // Navigate back to TTSScreen with full book data
54+ if ( ttsStore . currentBook ) {
55+ navigation . navigate ( 'TTSScreen' , { book : ttsStore . currentBook } ) ;
56+ } else if ( ttsStore . currentBookId ) {
5157 navigation . navigate ( 'TTSScreen' , { book : { id : ttsStore . currentBookId } as any } ) ;
5258 }
5359 ttsStore . setMiniPlayerVisible ( false ) ;
5460 } , [ navigation , ttsStore ] ) ;
5561
5662 const handleClose = useCallback ( async ( ) => {
57- await TrackPlayer . stop ( ) ;
5863 await TrackPlayer . reset ( ) ;
5964 ttsStore . setState ( 'idle' ) ;
6065 ttsStore . setMiniPlayerVisible ( false ) ;
@@ -84,20 +89,28 @@ export function TTSMiniPlayer() {
8489 < View style = { styles . content } >
8590 { /* Cover thumbnail */ }
8691 < TouchableOpacity onPress = { handleExpand } style = { styles . cover } >
87- < View style = { [ styles . coverInner , { backgroundColor : theme . colors . primary + '20' } ] } >
88- < Text style = { styles . coverText } >
89- { ttsStore . chapterTitle ?. charAt ( 0 ) || 'T' }
90- </ Text >
91- </ View >
92+ { ttsStore . currentBook ?. coverUrl ? (
93+ < Image
94+ source = { { uri : getCoverImageUrl ( ttsStore . currentBook . coverUrl ) } }
95+ style = { styles . coverImage }
96+ resizeMode = "cover"
97+ />
98+ ) : (
99+ < View style = { [ styles . coverInner , { backgroundColor : theme . colors . primary + '20' } ] } >
100+ < Text style = { styles . coverText } >
101+ { ( ttsStore . currentBook ?. title || 'T' ) . charAt ( 0 ) }
102+ </ Text >
103+ </ View >
104+ ) }
92105 </ TouchableOpacity >
93106
94107 { /* Info */ }
95108 < TouchableOpacity onPress = { handleExpand } style = { styles . info } >
96109 < Text style = { styles . title } numberOfLines = { 1 } >
97- { ttsStore . chapterTitle || '正在朗读' }
110+ { ttsStore . currentBook ?. title || ttsStore . chapterTitle || '正在朗读' }
98111 </ Text >
99112 < Text style = { styles . subtitle } numberOfLines = { 1 } >
100- 第 { ttsStore . currentParagraph + 1 } 段 / 共 { ttsStore . totalParagraphs } 段
113+ { ttsStore . chapterTitle } · 第 { ttsStore . currentParagraph + 1 } / { ttsStore . totalParagraphs } 段
101114 </ Text >
102115 </ TouchableOpacity >
103116
@@ -124,16 +137,11 @@ function createStyles(theme: ReturnType<typeof getTheme>) {
124137 return StyleSheet . create ( {
125138 container : {
126139 position : 'absolute' ,
127- bottom : 0 ,
140+ bottom : 48 ,
128141 left : 0 ,
129142 right : 0 ,
130143 borderTopLeftRadius : borderRadius . lg ,
131144 borderTopRightRadius : borderRadius . lg ,
132- shadowColor : '#000' ,
133- shadowOffset : { width : 0 , height : - 2 } ,
134- shadowOpacity : 0.1 ,
135- shadowRadius : 4 ,
136- elevation : 8 ,
137145 zIndex : 100 ,
138146 } ,
139147 progressBar : {
@@ -161,6 +169,10 @@ function createStyles(theme: ReturnType<typeof getTheme>) {
161169 justifyContent : 'center' ,
162170 alignItems : 'center' ,
163171 } ,
172+ coverImage : {
173+ width : '100%' ,
174+ height : '100%' ,
175+ } ,
164176 coverText : {
165177 fontSize : fontSizes . lg ,
166178 fontWeight : 'bold' ,
0 commit comments