1
1
use std:: time:: Duration ;
2
2
3
- use cursive:: {
4
- theme:: Style ,
5
- utils:: { markup:: StyledString , span:: SpannedString } ,
6
- } ;
7
-
8
3
use {
9
4
cursive:: {
10
5
event:: { Event , EventResult , MouseButton , MouseEvent } ,
11
- theme:: { ColorStyle , Effect } ,
6
+ theme:: { ColorStyle , Effect , Style } ,
12
7
traits:: View ,
8
+ utils:: { markup:: StyledString , span:: SpannedString } ,
13
9
view:: Nameable ,
14
10
CbSink , Cursive , Printer , XY ,
15
11
} ,
@@ -29,6 +25,7 @@ const SEEK_TIME: Duration = Duration::from_secs(10);
29
25
30
26
// Drawing constants
31
27
const SPACER : & ' static str = " " ;
28
+ const TICK : u32 = 5 ;
32
29
33
30
// A struct representing the view and state of the audio player.
34
31
pub struct PlayerView {
@@ -44,6 +41,12 @@ pub struct PlayerView {
44
41
timed_bool : ExpiringBool ,
45
42
// Whether or not the player is being shown.
46
43
is_visible : bool ,
44
+ // The elapsed playback time in whole seconds.
45
+ elapsed : usize ,
46
+ // The duration of the current track.
47
+ duration : usize ,
48
+ // The index of the current track.
49
+ index : usize ,
47
50
// The styled strings required to render the header and playlist.
48
51
lines : Vec < SpannedString < Style > > ,
49
52
// The vertical offset required to ensure the current track is visible in the playlist.
@@ -62,6 +65,9 @@ impl PlayerView {
62
65
mouse_seek_time : None ,
63
66
offset_y : 0 ,
64
67
is_visible : true ,
68
+ elapsed : 0 ,
69
+ duration : 0 ,
70
+ index : 0 ,
65
71
lines : Vec :: new ( ) ,
66
72
showing_volume : ExpiringBool :: new ( false , Duration :: from_millis ( 1500 ) ) ,
67
73
number_input : vec ! [ ] ,
@@ -74,36 +80,58 @@ impl PlayerView {
74
80
let cb_sink = siv. cb_sink ( ) . clone ( ) ;
75
81
let player_view = PlayerView :: new ( player, cb_sink) . with_name ( super :: ID ) ;
76
82
77
- siv. set_fps ( crate :: FPS ) ;
83
+ siv. set_fps ( TICK ) ;
78
84
siv. pop_layer ( ) ;
79
85
siv. add_layer ( player_view) ;
80
86
}
81
87
82
88
pub fn update_playlist ( & mut self , next : Playlist , set_playing : bool ) {
83
- _ = self . cb_sink . send ( Box :: new ( |siv| {
84
- siv. set_fps ( crate :: FPS ) ;
85
- } ) ) ;
86
-
87
89
let is_stopped = self . player . is_stopped ( ) ;
90
+
91
+ let volume = if self . player . is_muted {
92
+ 0.0
93
+ } else {
94
+ ( self . player . volume as f32 ) / 100.0
95
+ } ;
96
+
88
97
self . player . previous = Some ( self . player . current . clone ( ) ) ;
89
98
self . player . current = next;
90
99
self . player . stop ( ) ;
91
100
self . player . play ( ) ;
92
101
102
+ self . player . set_volume ( volume) ;
103
+
93
104
if !set_playing && is_stopped {
94
105
self . player . stop ( ) ;
95
106
}
96
107
97
108
self . lines . clear ( ) ;
98
- self . is_visible = true ;
109
+
110
+ self . show ( ) ;
99
111
}
100
112
101
113
pub fn hide ( & mut self ) {
102
114
self . is_visible = false ;
115
+
116
+ _ = self . cb_sink . send ( Box :: new ( |siv| {
117
+ siv. set_fps ( 0 ) ;
118
+ } ) ) ;
103
119
}
104
120
105
121
pub fn show ( & mut self ) {
106
122
self . is_visible = true ;
123
+
124
+ _ = self . cb_sink . send ( Box :: new ( |siv| {
125
+ siv. set_fps ( TICK ) ;
126
+ } ) ) ;
127
+ }
128
+
129
+ fn play_or_pause ( & mut self ) {
130
+ match self . player . status {
131
+ PlaybackStatus :: Paused => self . player . resume ( ) ,
132
+ PlaybackStatus :: Playing => self . player . pause ( ) ,
133
+ PlaybackStatus :: Stopped => self . player . play ( ) ,
134
+ } ;
107
135
}
108
136
109
137
fn increase_volume ( & mut self ) {
@@ -265,12 +293,12 @@ impl PlayerView {
265
293
let index = position. y - offset. y + self . offset_y - 1 ;
266
294
267
295
if index == self . player . current . index {
268
- self . player . play_or_pause ( ) ;
296
+ self . play_or_pause ( ) ;
269
297
} else {
270
298
self . player . play_index ( index) ;
271
299
}
272
300
}
273
- Area :: Background => _ = self . player . play_or_pause ( ) ,
301
+ Area :: Background => _ = self . play_or_pause ( ) ,
274
302
}
275
303
}
276
304
@@ -364,16 +392,6 @@ impl PlayerView {
364
392
format ! ( "{}vol: {:>3} %{}" , SPACER , self . player. volume, SPACER )
365
393
}
366
394
367
- // The elapsed playback time to display. When seeking with the mouse we use the
368
- // elapsed time had the seeking process completed.
369
- #[ inline]
370
- fn elapsed ( & self ) -> usize {
371
- match self . mouse_seek_time {
372
- Some ( t) if self . player . is_paused ( ) => t,
373
- _ => self . player . elapsed ( ) . as_secs ( ) as usize ,
374
- }
375
- }
376
-
377
395
// Computes the y offset needed to show the results of the fuzzy match.
378
396
#[ inline]
379
397
fn update_offset ( & self ) -> usize {
@@ -440,6 +458,14 @@ impl View for PlayerView {
440
458
}
441
459
}
442
460
461
+ self . elapsed = match self . mouse_seek_time {
462
+ Some ( t) if self . player . is_paused ( ) => t,
463
+ _ => self . player . elapsed ( ) . as_secs ( ) as usize ,
464
+ } ;
465
+
466
+ self . duration = self . player . current_file ( ) . duration ;
467
+ self . index = self . player . current . index ;
468
+
443
469
self . size = self . required_size ( size) ;
444
470
self . offset_y = self . update_offset ( ) ;
445
471
@@ -465,24 +491,23 @@ impl View for PlayerView {
465
491
}
466
492
467
493
let ( w, h) = ( self . size . x , self . size . y ) ;
468
- let f = self . player . current_file ( ) ;
469
- let duration_x = w. saturating_sub ( 9 ) ;
470
- let elapsed = self . elapsed ( ) ;
471
- let ( length, extra) = ratio ( elapsed, f. duration , w. saturating_sub ( 16 ) ) ;
494
+
495
+ let dur_col = w. saturating_sub ( 9 ) ;
472
496
473
497
// HEADER
474
498
if h > 1 {
475
499
// Artist + album + year
476
- if let Some ( entry) = self . lines . chunks ( 5 ) . nth ( self . player . current . index ) {
477
- if let Some ( header) = entry. get ( 4 ) {
500
+
501
+ if let Some ( line) = self . lines . chunks ( 5 ) . nth ( self . index ) {
502
+ if let Some ( header) = line. get ( 4 ) {
478
503
p. print_styled ( ( 0 , 0 ) , header) ;
479
504
}
480
505
}
481
506
482
507
// Volume
483
508
if self . showing_volume . is_true ( ) {
484
509
p. with_color ( ColorStyles :: prompt ( ) , |p| {
485
- p. print ( ( duration_x . saturating_sub ( 5 ) , 0 ) , & self . volume ( ) )
510
+ p. print ( ( dur_col . saturating_sub ( 5 ) , 0 ) , & self . volume ( ) )
486
511
} ) ;
487
512
} ;
488
513
}
@@ -525,38 +550,39 @@ impl View for PlayerView {
525
550
if let Some ( option) = self . playback_opts ( ) {
526
551
p. with_color ( ColorStyles :: info ( ) , |p| {
527
552
p. with_effect ( Effect :: Italic , |p| {
528
- p. print ( ( duration_x . saturating_sub ( 3 ) , row) , option)
553
+ p. print ( ( dur_col . saturating_sub ( 3 ) , row) , option)
529
554
} )
530
555
} )
531
556
}
532
557
}
533
558
534
559
// Duration
535
- p. print_styled ( ( duration_x , row) , duration_line) ;
560
+ p. print_styled ( ( dur_col , row) , duration_line) ;
536
561
}
537
562
538
563
// FOOTER
539
564
if h > 0 {
540
- let bottom_row = h - 1 ;
541
- let remaining = f. duration . saturating_sub ( elapsed) ;
565
+ let last_row = h - 1 ;
566
+ let ( length, extra) = ratio ( self . elapsed , self . duration , w. saturating_sub ( 16 ) ) ;
567
+ let remaining = self . duration . saturating_sub ( self . elapsed ) ;
542
568
543
569
// Elapsed time
544
570
p. with_color ( ColorStyles :: hl ( ) , |p| {
545
- p. print ( ( 0 , bottom_row ) , & mins_and_secs ( elapsed) ) ;
571
+ p. print ( ( 0 , last_row ) , & mins_and_secs ( self . elapsed ) ) ;
546
572
} ) ;
547
573
548
574
// Progress bar
549
575
p. with_color ( ColorStyles :: progress ( ) , |p| {
550
- p. print ( ( length + 8 , bottom_row ) , sub_block ( extra) ) ;
576
+ p. print ( ( length + 8 , last_row ) , sub_block ( extra) ) ;
551
577
} ) ;
552
578
p. cropped ( ( length + 8 , h) )
553
579
. with_color ( ColorStyles :: progress ( ) , |p| {
554
- p. print_hline ( ( 8 , bottom_row ) , length, "█" ) ;
580
+ p. print_hline ( ( 8 , last_row ) , length, "█" ) ;
555
581
} ) ;
556
582
557
583
// Remaining time
558
584
p. with_color ( ColorStyles :: hl ( ) , |p| {
559
- p. print ( ( duration_x , bottom_row ) , & mins_and_secs ( remaining) )
585
+ p. print ( ( dur_col , last_row ) , & mins_and_secs ( remaining) )
560
586
} ) ;
561
587
}
562
588
}
@@ -567,7 +593,7 @@ impl View for PlayerView {
567
593
568
594
if let Some ( action) = PLAYER_EVENT_TO_ACTION . get ( & event) {
569
595
match action {
570
- PlayOrPause => self . player . play_or_pause ( ) ,
596
+ PlayOrPause => self . play_or_pause ( ) ,
571
597
Stop => self . player . stop ( ) ,
572
598
Next => self . next ( ) ,
573
599
Previous => self . previous ( ) ,
0 commit comments