@@ -15,7 +15,7 @@ use std::{
1515} ;
1616
1717use anyhow:: { anyhow, Context , Result } ;
18- use eframe:: egui:: { Button , CollapsingHeader , RichText } ;
18+ use eframe:: egui:: { Button , CollapsingHeader , Label , RichText } ;
1919use eframe:: epaint:: { Pos2 , Vec2 } ;
2020use eframe:: {
2121 egui:: { self , FontSelection , Layout , TextFormat , Ui } ,
@@ -43,6 +43,7 @@ use find_string::FindString;
4343use message:: MessageHandle ;
4444use request_counter:: { RequestCounter , RequestID } ;
4545
46+ use self :: message:: ModDetails ;
4647use self :: toggle_switch:: toggle_switch;
4748
4849pub fn gui ( args : Option < Vec < String > > ) -> Result < ( ) > {
@@ -98,10 +99,14 @@ pub struct App {
9899 lint_report : Option < LintReport > ,
99100 lints_toggle_window : Option < WindowLintsToggle > ,
100101 lint_options : LintOptions ,
101- cache : CommonMarkCache ,
102+ update_cmark_cache : CommonMarkCache ,
102103 needs_restart : bool ,
103104 self_update_rid : Option < MessageHandle < SelfUpdateProgress > > ,
104105 original_exe_path : Option < PathBuf > ,
106+ detailed_mod_info_window : Option < WindowDetailedModInfo > ,
107+ mod_details : Option < ModDetails > ,
108+ fetch_mod_details_rid : Option < MessageHandle < ( ) > > ,
109+ mod_details_thumbnail_texture_handle : Option < egui:: TextureHandle > ,
105110}
106111
107112#[ derive( Default ) ]
@@ -157,10 +162,14 @@ impl App {
157162 lint_report : None ,
158163 lints_toggle_window : None ,
159164 lint_options : LintOptions :: default ( ) ,
160- cache : Default :: default ( ) ,
165+ update_cmark_cache : Default :: default ( ) ,
161166 needs_restart : false ,
162167 self_update_rid : None ,
163168 original_exe_path : None ,
169+ detailed_mod_info_window : None ,
170+ mod_details : None ,
171+ fetch_mod_details_rid : None ,
172+ mod_details_thumbnail_texture_handle : None ,
164173 } )
165174 }
166175
@@ -434,6 +443,25 @@ impl App {
434443 ui. output_mut ( |o| o. copied_text = mc. spec . url . to_owned ( ) ) ;
435444 }
436445
446+ if let Some ( modio_id) = info. modio_id
447+ && let Some ( modio_provider_params) = self . state . config . provider_parameters . get ( "modio" )
448+ && let Some ( oauth_token) = modio_provider_params. get ( "oauth" )
449+ && ui
450+ . button ( "ℹ" )
451+ . on_hover_text_at_pointer ( "View details" )
452+ . clicked ( )
453+ {
454+ self . detailed_mod_info_window =
455+ Some ( WindowDetailedModInfo { info : info. clone ( ) } ) ;
456+ self . fetch_mod_details_rid = Some ( message:: FetchModDetails :: send (
457+ & mut self . request_counter ,
458+ ui. ctx ( ) ,
459+ self . tx . clone ( ) ,
460+ oauth_token,
461+ modio_id
462+ ) ) ;
463+ }
464+
437465 if mc. enabled {
438466 let is_duplicate = enabled_specs. iter ( ) . any ( |( i, spec) | {
439467 Some ( state. index ) != * i && info. spec . satisfies_dependency ( spec)
@@ -730,7 +758,7 @@ impl App {
730758 . show ( ctx, |ui| {
731759 CommonMarkViewer :: new ( "available-update" )
732760 . max_image_width ( Some ( 512 ) )
733- . show ( ui, & mut self . cache , & update. body ) ;
761+ . show ( ui, & mut self . update_cmark_cache , & update. body ) ;
734762 ui. with_layout ( egui:: Layout :: right_to_left ( Align :: TOP ) , |ui| {
735763 if ui
736764 . add ( egui:: Button :: new ( "Install update" ) )
@@ -1400,6 +1428,129 @@ impl App {
14001428 }
14011429 }
14021430 }
1431+
1432+ fn show_detailed_mod_info ( & mut self , ctx : & egui:: Context ) {
1433+ if let Some ( WindowDetailedModInfo { info } ) = & self . detailed_mod_info_window {
1434+ egui:: Area :: new ( "detailed-mod-info-overlay" )
1435+ . movable ( false )
1436+ . fixed_pos ( Pos2 :: ZERO )
1437+ . order ( egui:: Order :: Background )
1438+ . show ( ctx, |ui| {
1439+ egui:: Frame :: none ( )
1440+ . fill ( Color32 :: from_rgba_unmultiplied ( 0 , 0 , 0 , 127 ) )
1441+ . show ( ui, |ui| {
1442+ ui. allocate_space ( ui. available_size ( ) ) ;
1443+ } )
1444+ } ) ;
1445+
1446+ let mut open = true ;
1447+
1448+ egui:: Window :: new ( & info. name )
1449+ . open ( & mut open)
1450+ . collapsible ( false )
1451+ . anchor ( Align2 :: CENTER_TOP , Vec2 :: new ( 0.0 , 30.0 ) )
1452+ . resizable ( false )
1453+ . show ( ctx, |ui| self . show_detailed_mod_info_inner ( ui) ) ;
1454+
1455+ if !open {
1456+ self . detailed_mod_info_window = None ;
1457+ self . mod_details = None ;
1458+ self . fetch_mod_details_rid = None ;
1459+ self . mod_details_thumbnail_texture_handle = None ;
1460+ }
1461+ }
1462+ }
1463+
1464+ fn show_detailed_mod_info_inner ( & mut self , ui : & mut egui:: Ui ) {
1465+ if let Some ( mod_details) = & self . mod_details {
1466+ let scroll_area_height = ( ui. available_height ( ) - 60.0 ) . clamp ( 0.0 , f32:: INFINITY ) ;
1467+
1468+ egui:: ScrollArea :: vertical ( )
1469+ . max_height ( scroll_area_height)
1470+ . max_width ( f32:: INFINITY )
1471+ . auto_shrink ( [ false , false ] )
1472+ . stick_to_right ( true )
1473+ . show ( ui, |ui| {
1474+ let texture: & egui:: TextureHandle = self
1475+ . mod_details_thumbnail_texture_handle
1476+ . get_or_insert_with ( || {
1477+ ui. ctx ( ) . load_texture (
1478+ format ! ( "{} image" , mod_details. r#mod. name) ,
1479+ {
1480+ let image =
1481+ image:: load_from_memory ( & mod_details. thumbnail ) . unwrap ( ) ;
1482+ let size = [ image. width ( ) as _ , image. height ( ) as _ ] ;
1483+ let image_buffer = image. to_rgb8 ( ) ;
1484+ let pixels = image_buffer. as_flat_samples ( ) ;
1485+ egui:: ColorImage :: from_rgb ( size, pixels. as_slice ( ) )
1486+ } ,
1487+ Default :: default ( ) ,
1488+ )
1489+ } ) ;
1490+ ui. vertical_centered ( |ui| {
1491+ ui. image ( texture, texture. size_vec2 ( ) ) ;
1492+ } ) ;
1493+
1494+ ui. heading ( "Uploader" ) ;
1495+ ui. label ( & mod_details. r#mod . submitted_by . username ) ;
1496+ ui. add_space ( 10.0 ) ;
1497+
1498+ ui. heading ( "Description" ) ;
1499+ if let Some ( desc) = & mod_details. r#mod . description_plaintext {
1500+ ui. label ( desc) ;
1501+ } else {
1502+ ui. label ( "No description provided." ) ;
1503+ }
1504+ ui. add_space ( 10.0 ) ;
1505+
1506+ ui. heading ( "Versions and changelog" ) ;
1507+ ui. label (
1508+ RichText :: new ( "Only the 10 most recent versions are shown." )
1509+ . color ( Color32 :: GRAY )
1510+ . italics ( ) ,
1511+ ) ;
1512+ egui:: Grid :: new ( "mod-details-available-versions" )
1513+ . spacing ( Vec2 :: new ( 3.0 , 10.0 ) )
1514+ . striped ( true )
1515+ . num_columns ( 2 )
1516+ . show ( ui, |ui| {
1517+ mod_details. versions . iter ( ) . for_each ( |file| {
1518+ if let Some ( version) = & file. version {
1519+ ui. label ( version) ;
1520+ } else {
1521+ ui. label ( "Unknown version" ) ;
1522+ }
1523+ if let Some ( changelog) = & file. changelog {
1524+ ui. add ( Label :: new ( changelog) . wrap ( true ) ) ;
1525+ } else {
1526+ ui. label ( "N/A" ) ;
1527+ }
1528+ ui. end_row ( ) ;
1529+ } ) ;
1530+ } ) ;
1531+ ui. add_space ( 10.0 ) ;
1532+
1533+ ui. heading ( "Files" ) ;
1534+ if let Some ( file) = & mod_details. r#mod . modfile {
1535+ ui. horizontal ( |ui| {
1536+ if let Some ( version) = & file. version {
1537+ ui. label ( version) ;
1538+ } else {
1539+ ui. label ( "Unknown version" ) ;
1540+ }
1541+ ui. hyperlink ( & file. download . binary_url ) ;
1542+ } ) ;
1543+ } else {
1544+ ui. label ( "No files provided." ) ;
1545+ }
1546+ } ) ;
1547+ } else {
1548+ ui. horizontal ( |ui| {
1549+ ui. spinner ( ) ;
1550+ ui. label ( "Fetching mod details from mod.io..." ) ;
1551+ } ) ;
1552+ }
1553+ }
14031554}
14041555
14051556struct WindowProviderParameters {
@@ -1456,6 +1607,10 @@ struct WindowLintsToggle {
14561607 mods : Vec < ModSpecification > ,
14571608}
14581609
1610+ struct WindowDetailedModInfo {
1611+ info : ModInfo ,
1612+ }
1613+
14591614impl eframe:: App for App {
14601615 fn update ( & mut self , ctx : & egui:: Context , _frame : & mut eframe:: Frame ) {
14611616 if self . needs_restart
@@ -1491,6 +1646,7 @@ impl eframe::App for App {
14911646 self . show_settings ( ctx) ;
14921647 self . show_lints_toggle ( ctx) ;
14931648 self . show_lint_report ( ctx) ;
1649+ self . show_detailed_mod_info ( ctx) ;
14941650
14951651 egui:: TopBottomPanel :: bottom ( "bottom_panel" ) . show ( ctx, |ui| {
14961652 ui. with_layout ( egui:: Layout :: right_to_left ( Align :: TOP ) , |ui| {
@@ -1499,6 +1655,8 @@ impl eframe::App for App {
14991655 && self . update_rid . is_none ( )
15001656 && self . lint_rid . is_none ( )
15011657 && self . self_update_rid . is_none ( )
1658+ && self . detailed_mod_info_window . is_none ( )
1659+ && self . fetch_mod_details_rid . is_none ( )
15021660 && self . state . config . drg_pak_path . is_some ( ) ,
15031661 |ui| {
15041662 if let Some ( args) = & self . args {
0 commit comments