1+ use ratatui_kit:: prelude:: * ;
2+ use ratatui_kit:: ratatui:: {
3+ style:: { Modifier , Style } ,
4+ text:: { Line , Span } ,
5+ } ;
6+ use ratatui_kit:: ratatui:: layout:: Direction ;
7+
8+ #[ derive( Debug , Clone , Props ) ]
9+ pub struct ProgressBarProps {
10+ pub style : Style ,
11+ pub menu_style : Style ,
12+ pub install_message : String ,
13+ pub stage : String ,
14+ pub percent : f64 ,
15+ pub downloaded : u64 ,
16+ pub total : u64 ,
17+ pub speed : f64 ,
18+ }
19+
20+ impl Default for ProgressBarProps {
21+ fn default ( ) -> Self {
22+ Self {
23+ style : Style :: default ( ) ,
24+ menu_style : Style :: default ( ) ,
25+ install_message : String :: new ( ) ,
26+ stage : String :: new ( ) ,
27+ percent : 0.0 ,
28+ downloaded : 0 ,
29+ total : 0 ,
30+ speed : 0.0 ,
31+ }
32+ }
33+ }
34+
35+ #[ component]
36+ pub fn ProgressBar (
37+ _hooks : Hooks ,
38+ props : & ProgressBarProps ,
39+ ) -> impl Into < AnyElement < ' static > > {
40+ // 计算进度条
41+ let percent = props. percent . clamp ( 0.0 , 100.0 ) ;
42+ const BAR_WIDTH : usize = 30 ;
43+ let fill = ( ( percent / 100.0 * BAR_WIDTH as f64 ) as usize ) . min ( BAR_WIDTH ) ;
44+ let bar = format ! ( "[{}{}]" , "█" . repeat( fill) , "░" . repeat( BAR_WIDTH - fill) ) ;
45+
46+ let mut spans = vec ! [
47+ Span :: styled( bar, props. menu_style) ,
48+ Span :: raw( format!( " {:.2}%" , percent) ) ,
49+ ] ;
50+
51+ if props. stage . contains ( "Downloading" ) {
52+ let mb = props. downloaded as f64 / 1024.0 / 1024.0 ;
53+ let total_mb = props. total as f64 / 1024.0 / 1024.0 ;
54+ let speed_mb = props. speed / 1024.0 / 1024.0 ;
55+ spans. push ( Span :: raw ( format ! ( " ({:.2} MB/{:.2} MB)" , mb, total_mb) ) ) ;
56+ spans. push ( Span :: raw ( format ! ( " {:.2} MB/s" , speed_mb) ) ) ;
57+ } else {
58+ spans. push ( Span :: raw ( format ! ( " {} / {}" , props. downloaded, props. total) ) ) ;
59+ }
60+
61+ // 官方标准 element! 语法(零错误)
62+ element ! {
63+ View ( flex_direction: Direction :: Vertical ) {
64+ // 必须传 String,不能传 &str
65+ Text ( text: props. install_message. clone( ) , style: props. style. add_modifier( Modifier :: BOLD ) ) { }
66+ Text ( text: String :: new( ) ) { }
67+
68+ // 官方条件渲染:#(if ...)
69+ #( if !props. stage. is_empty( ) {
70+ Some ( element! {
71+ View {
72+ Text ( text: props. stage. clone( ) , style: props. style. add_modifier( Modifier :: BOLD ) ) { }
73+ // Text(spans: spans) {}
74+ }
75+ } )
76+ } else {
77+ None
78+ } )
79+ }
80+ }
81+ }
0 commit comments