2023-04-23 20:53:51 +08:00
import ' dart:convert ' ;
2023-04-20 18:10:06 +08:00
import ' package:flutter/material.dart ' ;
2023-04-20 20:57:47 +08:00
import ' package:flutter/services.dart ' ;
import ' package:flutter_hbb/models/model.dart ' ;
2023-04-20 18:10:06 +08:00
import ' package:provider/provider.dart ' ;
2023-04-21 21:40:34 +08:00
// to-do: do not depend on desktop
2023-04-20 20:57:47 +08:00
import ' package:flutter_hbb/desktop/widgets/remote_toolbar.dart ' ;
import ' package:flutter_hbb/models/platform_model.dart ' ;
2023-04-20 18:10:06 +08:00
2023-04-20 22:53:43 +08:00
import ' ./desc.dart ' ;
import ' ./model.dart ' ;
import ' ./common.dart ' ;
2023-04-20 18:10:06 +08:00
2023-04-20 22:53:43 +08:00
class LocationItem extends StatelessWidget {
2023-04-20 18:10:06 +08:00
final String peerId ;
2023-04-20 20:57:47 +08:00
final FFI ffi ;
final String location ;
2023-04-20 18:10:06 +08:00
final LocationModel locationModel ;
2023-04-20 22:53:43 +08:00
LocationItem ( {
2023-04-20 18:10:06 +08:00
Key ? key ,
required this . peerId ,
2023-04-20 20:57:47 +08:00
required this . ffi ,
required this . location ,
2023-04-20 18:10:06 +08:00
required this . locationModel ,
} ) : super ( key: key ) ;
2023-04-20 20:57:47 +08:00
bool get isEmpty = > locationModel . isEmpty ;
2023-04-20 22:53:43 +08:00
static LocationItem createLocationItem (
String peerId , FFI ffi , String location ) {
final model = addLocation ( location ) ;
return LocationItem (
peerId: peerId ,
ffi: ffi ,
location: location ,
locationModel: model ,
) ;
}
2023-04-20 18:10:06 +08:00
@ override
Widget build ( BuildContext context ) {
return ChangeNotifierProvider . value (
value: locationModel ,
child: Consumer < LocationModel > ( builder: ( context , model , child ) {
return Column (
2023-04-20 22:53:43 +08:00
children: model . pluginModels . entries
. map ( ( entry ) = > _buildPluginItem ( entry . key , entry . value ) )
. toList ( ) ,
) ;
} ) ,
) ;
}
Widget _buildPluginItem ( PluginId id , PluginModel model ) = > PluginItem (
pluginId: id ,
peerId: peerId ,
ffi: ffi ,
location: location ,
pluginModel: model ,
) ;
}
class PluginItem extends StatelessWidget {
final PluginId pluginId ;
final String peerId ;
final FFI ffi ;
final String location ;
final PluginModel pluginModel ;
PluginItem ( {
Key ? key ,
required this . pluginId ,
required this . peerId ,
required this . ffi ,
required this . location ,
required this . pluginModel ,
2023-04-21 23:25:00 +08:00
} ) : super ( key: key ) ;
2023-04-20 22:53:43 +08:00
bool get isEmpty = > pluginModel . isEmpty ;
@ override
Widget build ( BuildContext context ) {
2023-04-21 23:25:00 +08:00
return ChangeNotifierProvider . value (
value: pluginModel ,
child: Consumer < PluginModel > (
builder: ( context , pluginModel , child ) {
2023-04-21 21:40:34 +08:00
return Column (
children: pluginModel . uiList . map ( ( ui ) = > _buildItem ( ui ) ) . toList ( ) ,
) ;
} ,
) ,
2023-04-20 18:10:06 +08:00
) ;
}
2023-04-20 20:57:47 +08:00
Widget _buildItem ( UiType ui ) {
2023-04-21 21:40:34 +08:00
late Widget child ;
2023-04-20 20:57:47 +08:00
switch ( ui . runtimeType ) {
case UiButton:
2023-04-21 21:40:34 +08:00
child = _buildMenuButton ( ui as UiButton ) ;
break ;
2023-04-20 20:57:47 +08:00
case UiCheckbox:
2023-04-21 21:40:34 +08:00
child = _buildCheckboxMenuButton ( ui as UiCheckbox ) ;
break ;
2023-04-20 20:57:47 +08:00
default :
2023-04-21 21:40:34 +08:00
child = Container ( ) ;
2023-04-20 20:57:47 +08:00
}
2023-04-21 21:40:34 +08:00
// to-do: add plugin icon and tooltip
return child ;
2023-04-20 20:57:47 +08:00
}
Uint8List _makeEvent (
String key , {
bool ? v ,
} ) {
final event = MsgFromUi (
id: pluginId ,
name: getDesc ( pluginId ) ? . name ? ? ' ' ,
location: location ,
key: key ,
value:
v ! = null ? ( v ? ConfigItem . trueValue : ConfigItem . falseValue ) : ' ' ,
action: ' ' ,
) ;
return Uint8List . fromList ( event . toString ( ) . codeUnits ) ;
}
Widget _buildMenuButton ( UiButton ui ) {
return MenuButton (
2023-04-21 21:40:34 +08:00
onPressed: ( ) = > bind . pluginEvent (
id: pluginId ,
peer: peerId ,
event: _makeEvent ( ui . key ) ,
) ,
2023-04-23 16:23:35 +08:00
// to-do: support trailing icon, but it will cause tree shake error.
// ```
// This application cannot tree shake icons fonts. It has non-constant instances of IconData at the following locations:
// Target release_macos_bundle_flutter_assets failed: Exception: Avoid non-constant invocations of IconData or try to build again with --no-tree-shake-icons.
// ```
//
// trailingIcon: Icon(
// IconData(int.parse(ui.icon, radix: 16), fontFamily: 'MaterialIcons')),
//
2023-04-20 22:53:43 +08:00
// to-do: RustDesk translate or plugin translate ?
2023-04-20 20:57:47 +08:00
child: Text ( ui . text ) ,
ffi: ffi ,
) ;
}
2023-04-21 23:25:00 +08:00
String ? getOption ( OptionModel model , String key ) {
var v = model . value ;
2023-04-21 21:40:34 +08:00
if ( v = = null ) {
if ( peerId . isEmpty ) {
2023-04-23 15:40:55 +08:00
v = bind . pluginGetSharedOption ( id: pluginId , key: key ) ;
2023-04-21 21:40:34 +08:00
} else {
2023-04-21 23:25:00 +08:00
v = bind . pluginGetSessionOption ( id: pluginId , peer: peerId , key: key ) ;
2023-04-21 21:40:34 +08:00
}
}
2023-04-21 23:25:00 +08:00
return v ;
}
Widget _buildCheckboxMenuButton ( UiCheckbox ui ) {
getChild ( OptionModel model ) {
final v = getOption ( model , ui . key ) ;
if ( v = = null ) {
// session or plugin not found
return Container ( ) ;
}
return CkbMenuButton (
value: ConfigItem . isTrue ( v ) ,
onChanged: ( v ) {
if ( v ! = null ) {
bind . pluginEvent (
id: pluginId ,
peer: peerId ,
event: _makeEvent ( ui . key , v: v ) ,
) ;
}
} ,
// to-do: RustDesk translate or plugin translate ?
child: Text ( ui . text ) ,
ffi: ffi ,
) ;
2023-04-20 22:53:43 +08:00
}
2023-04-21 23:25:00 +08:00
final optionModel = addOptionModel ( location , pluginId , peerId , ui . key ) ;
return ChangeNotifierProvider . value (
value: optionModel ,
child: Consumer < OptionModel > (
builder: ( context , model , child ) {
return getChild ( model ) ;
} ,
) ,
2023-04-20 20:57:47 +08:00
) ;
}
2023-04-20 18:10:06 +08:00
}
2023-04-20 22:53:43 +08:00
void handleReloading ( Map < String , dynamic > evt , String peer ) {
if ( evt [ ' id ' ] = = null | | evt [ ' location ' ] = = null ) {
return ;
}
2023-04-23 20:53:51 +08:00
try {
final ui = UiType . create ( json . decode ( evt [ ' ui ' ] as String ) ) ;
if ( ui ! = null ) {
addLocationUi ( evt [ ' location ' ] ! , evt [ ' id ' ] ! , ui ) ;
}
} catch ( e ) {
debugPrint ( ' Failed handleReloading, json decode of ui, $ e ' ) ;
}
2023-04-21 21:40:34 +08:00
}
void handleOption ( Map < String , dynamic > evt , String peer ) {
updateOption (
evt [ ' location ' ] , evt [ ' id ' ] , evt [ ' peer ' ] ? ? ' ' , evt [ ' key ' ] , evt [ ' value ' ] ) ;
2023-04-20 22:53:43 +08:00
}