2022-09-08 18:25:19 +03:00
import ' dart:io ' ;
2022-09-13 17:24:06 +03:00
import ' dart:math ' as math ;
2022-09-08 18:25:19 +03:00
2022-08-26 18:28:08 +03:00
import ' package:flutter/material.dart ' ;
import ' package:flutter/services.dart ' ;
import ' package:flutter_hbb/models/chat_model.dart ' ;
import ' package:get/get.dart ' ;
2022-09-01 09:02:02 +03:00
import ' package:rxdart/rxdart.dart ' as rxdart ;
2022-08-26 18:28:08 +03:00
import ' ../../common.dart ' ;
import ' ../../mobile/widgets/dialog.dart ' ;
import ' ../../models/model.dart ' ;
import ' ../../models/platform_model.dart ' ;
2022-08-29 13:48:12 +03:00
import ' ../../common/shared_state.dart ' ;
2022-08-26 18:28:08 +03:00
import ' ./popup_menu.dart ' ;
2022-08-28 16:55:16 +03:00
import ' ./material_mod_popup_menu.dart ' as mod_menu ;
2022-09-08 10:35:19 +03:00
import ' ./utils.dart ' ;
2022-08-26 18:28:08 +03:00
class _MenubarTheme {
static const Color commonColor = MyTheme . accent ;
2022-08-29 13:48:12 +03:00
// kMinInteractiveDimension
2022-09-01 13:56:12 +03:00
static const double height = 25.0 ;
2022-08-29 13:48:12 +03:00
static const double dividerHeight = 12.0 ;
2022-08-26 18:28:08 +03:00
}
class RemoteMenubar extends StatefulWidget {
final String id ;
final FFI ffi ;
2022-09-14 05:10:55 +03:00
final Function ( Function ( bool ) ) onEnterOrLeaveImageSetter ;
final Function ( ) onEnterOrLeaveImageCleaner ;
2022-08-26 18:28:08 +03:00
const RemoteMenubar ( {
Key ? key ,
required this . id ,
required this . ffi ,
2022-09-14 05:10:55 +03:00
required this . onEnterOrLeaveImageSetter ,
required this . onEnterOrLeaveImageCleaner ,
2022-08-26 18:28:08 +03:00
} ) : super ( key: key ) ;
@ override
State < RemoteMenubar > createState ( ) = > _RemoteMenubarState ( ) ;
}
class _RemoteMenubarState extends State < RemoteMenubar > {
final RxBool _show = false . obs ;
final Rx < Color > _hideColor = Colors . white12 . obs ;
2022-09-13 16:59:06 +03:00
final _rxHideReplay = rxdart . ReplaySubject < int > ( ) ;
final _pinMenubar = false . obs ;
bool _isCursorOverImage = false ;
2022-08-26 18:28:08 +03:00
bool get isFullscreen = > Get . find < RxBool > ( tag: ' fullscreen ' ) . isTrue ;
2022-09-13 16:59:06 +03:00
void _setFullscreen ( bool v ) {
2022-08-26 18:28:08 +03:00
Get . find < RxBool > ( tag: ' fullscreen ' ) . value = v ;
}
2022-09-13 16:59:06 +03:00
@ override
2022-09-14 05:10:55 +03:00
initState ( ) {
2022-09-13 16:59:06 +03:00
super . initState ( ) ;
2022-09-14 05:10:55 +03:00
widget . onEnterOrLeaveImageSetter ( ( enter ) {
2022-09-13 16:59:06 +03:00
if ( enter ) {
_rxHideReplay . add ( 0 ) ;
_isCursorOverImage = true ;
} else {
_isCursorOverImage = false ;
}
} ) ;
_rxHideReplay
. throttleTime ( const Duration ( milliseconds: 5000 ) ,
trailing: true , leading: false )
. listen ( ( int v ) {
if ( _pinMenubar . isFalse & & _show . isTrue & & _isCursorOverImage ) {
_show . value = false ;
}
} ) ;
}
2022-09-14 05:10:55 +03:00
@ override
dispose ( ) {
super . dispose ( ) ;
widget . onEnterOrLeaveImageCleaner ( ) ;
}
2022-08-26 18:28:08 +03:00
@ override
Widget build ( BuildContext context ) {
return Align (
alignment: Alignment . topCenter ,
child: Obx (
( ) = > _show . value ? _buildMenubar ( context ) : _buildShowHide ( context ) ) ,
) ;
}
Widget _buildShowHide ( BuildContext context ) {
2022-08-28 16:55:16 +03:00
return Obx ( ( ) = > Tooltip (
2022-09-14 05:10:55 +03:00
message: translate ( _show . value ? " Hide Menubar " : " Show Menubar " ) ,
child: SizedBox (
width: 100 ,
height: 13 ,
child: TextButton (
onHover: ( bool v ) {
_hideColor . value = v ? Colors . white60 : Colors . white24 ;
} ,
onPressed: ( ) {
_show . value = ! _show . value ;
} ,
child: Obx ( ( ) = > Container (
color: _hideColor . value ,
) . marginOnly ( bottom: 8.0 ) ) ) ) ) ) ;
2022-08-26 18:28:08 +03:00
}
Widget _buildMenubar ( BuildContext context ) {
final List < Widget > menubarItems = [ ] ;
if ( ! isWebDesktop ) {
2022-09-13 16:59:06 +03:00
menubarItems . add ( _buildPinMenubar ( context ) ) ;
2022-08-26 18:28:08 +03:00
menubarItems . add ( _buildFullscreen ( context ) ) ;
2022-09-08 17:18:02 +03:00
if ( widget . ffi . ffiModel . isPeerAndroid ) {
menubarItems . add ( IconButton (
tooltip: translate ( ' Mobile Actions ' ) ,
color: _MenubarTheme . commonColor ,
icon: const Icon ( Icons . build ) ,
onPressed: ( ) {
widget . ffi . dialogManager
. toggleMobileActionsOverlay ( ffi: widget . ffi ) ;
} ,
) ) ;
}
2022-08-26 18:28:08 +03:00
}
menubarItems . add ( _buildMonitor ( context ) ) ;
menubarItems . add ( _buildControl ( context ) ) ;
menubarItems . add ( _buildDisplay ( context ) ) ;
2022-09-05 17:18:29 +03:00
menubarItems . add ( _buildKeyboard ( context ) ) ;
2022-08-26 18:28:08 +03:00
if ( ! isWeb ) {
menubarItems . add ( _buildChat ( context ) ) ;
}
menubarItems . add ( _buildClose ( context ) ) ;
return PopupMenuTheme (
2022-08-28 16:55:16 +03:00
data: const PopupMenuThemeData (
2022-08-26 18:28:08 +03:00
textStyle: TextStyle ( color: _MenubarTheme . commonColor ) ) ,
child: Column ( mainAxisSize: MainAxisSize . min , children: [
Container (
color: Colors . white ,
child: Row (
mainAxisSize: MainAxisSize . min ,
children: menubarItems ,
) ) ,
_buildShowHide ( context ) ,
] ) ) ;
}
2022-09-13 16:59:06 +03:00
Widget _buildPinMenubar ( BuildContext context ) {
2022-09-13 17:24:06 +03:00
return Obx ( ( ) = > IconButton (
tooltip:
translate ( _pinMenubar . isTrue ? ' Unpin menubar ' : ' Pin menubar ' ) ,
onPressed: ( ) {
_pinMenubar . value = ! _pinMenubar . value ;
} ,
icon: Obx ( ( ) = > Transform . rotate (
angle: _pinMenubar . isTrue ? math . pi / 4 : 0 ,
child: Icon (
Icons . push_pin ,
color: _pinMenubar . isTrue
? _MenubarTheme . commonColor
: Colors . grey ,
) ) ) ,
) ) ;
2022-09-13 16:59:06 +03:00
}
2022-08-26 18:28:08 +03:00
Widget _buildFullscreen ( BuildContext context ) {
return IconButton (
tooltip: translate ( isFullscreen ? ' Exit Fullscreen ' : ' Fullscreen ' ) ,
onPressed: ( ) {
2022-09-13 16:59:06 +03:00
_setFullscreen ( ! isFullscreen ) ;
2022-08-26 18:28:08 +03:00
} ,
icon: Obx ( ( ) = > isFullscreen
2022-08-28 16:55:16 +03:00
? const Icon (
2022-08-26 18:28:08 +03:00
Icons . fullscreen_exit ,
color: _MenubarTheme . commonColor ,
)
2022-08-28 16:55:16 +03:00
: const Icon (
2022-08-26 18:28:08 +03:00
Icons . fullscreen ,
color: _MenubarTheme . commonColor ,
) ) ,
) ;
}
Widget _buildChat ( BuildContext context ) {
return IconButton (
tooltip: translate ( ' Chat ' ) ,
onPressed: ( ) {
widget . ffi . chatModel . changeCurrentID ( ChatModel . clientModeID ) ;
widget . ffi . chatModel . toggleChatOverlay ( ) ;
} ,
2022-08-28 16:55:16 +03:00
icon: const Icon (
2022-08-26 18:28:08 +03:00
Icons . message ,
color: _MenubarTheme . commonColor ,
) ,
) ;
}
Widget _buildMonitor ( BuildContext context ) {
final pi = widget . ffi . ffiModel . pi ;
2022-08-28 16:55:16 +03:00
return mod_menu . PopupMenuButton (
2022-08-26 18:28:08 +03:00
tooltip: translate ( ' Select Monitor ' ) ,
padding: EdgeInsets . zero ,
2022-08-28 16:55:16 +03:00
position: mod_menu . PopupMenuPosition . under ,
2022-08-26 18:28:08 +03:00
icon: Stack (
alignment: Alignment . center ,
children: [
2022-08-28 16:55:16 +03:00
const Icon (
2022-08-26 18:28:08 +03:00
Icons . personal_video ,
color: _MenubarTheme . commonColor ,
) ,
Padding (
2022-08-28 16:55:16 +03:00
padding: const EdgeInsets . only ( bottom: 3.9 ) ,
2022-08-26 18:28:08 +03:00
child: Obx ( ( ) {
RxInt display = CurrentDisplayState . find ( widget . id ) ;
return Text (
" ${ display . value + 1 } / ${ pi . displays . length } " ,
2022-08-28 16:55:16 +03:00
style: const TextStyle (
color: _MenubarTheme . commonColor , fontSize: 8 ) ,
2022-08-26 18:28:08 +03:00
) ;
} ) ,
)
] ,
) ,
itemBuilder: ( BuildContext context ) {
final List < Widget > rowChildren = [ ] ;
for ( int i = 0 ; i < pi . displays . length ; i + + ) {
2022-08-29 13:48:12 +03:00
rowChildren . add (
Stack (
2022-08-26 18:28:08 +03:00
alignment: Alignment . center ,
children: [
2022-08-28 16:55:16 +03:00
const Icon (
2022-08-26 18:28:08 +03:00
Icons . personal_video ,
color: _MenubarTheme . commonColor ,
) ,
TextButton (
child: Container (
alignment: AlignmentDirectional . center ,
constraints:
2022-08-28 16:55:16 +03:00
const BoxConstraints ( minHeight: _MenubarTheme . height ) ,
2022-08-26 18:28:08 +03:00
child: Padding (
2022-08-28 16:55:16 +03:00
padding: const EdgeInsets . only ( bottom: 2.5 ) ,
2022-08-26 18:28:08 +03:00
child: Text (
( i + 1 ) . toString ( ) ,
2022-08-28 16:55:16 +03:00
style:
const TextStyle ( color: _MenubarTheme . commonColor ) ,
2022-08-26 18:28:08 +03:00
) ,
) ) ,
onPressed: ( ) {
RxInt display = CurrentDisplayState . find ( widget . id ) ;
if ( display . value ! = i ) {
bind . sessionSwitchDisplay ( id: widget . id , value: i ) ;
pi . currentDisplay = i ;
display . value = i ;
}
} ,
)
] ,
) ,
2022-08-29 13:48:12 +03:00
) ;
2022-08-26 18:28:08 +03:00
}
2022-08-28 16:55:16 +03:00
return < mod_menu . PopupMenuEntry < String > > [
mod_menu . PopupMenuItem < String > (
2022-08-26 18:28:08 +03:00
height: _MenubarTheme . height ,
padding: EdgeInsets . zero ,
child: Row (
mainAxisAlignment: MainAxisAlignment . center ,
children: rowChildren ) ,
)
] ;
} ,
) ;
}
Widget _buildControl ( BuildContext context ) {
2022-08-28 16:55:16 +03:00
return mod_menu . PopupMenuButton (
2022-08-26 18:28:08 +03:00
padding: EdgeInsets . zero ,
2022-08-28 16:55:16 +03:00
icon: const Icon (
2022-08-26 18:28:08 +03:00
Icons . bolt ,
color: _MenubarTheme . commonColor ,
) ,
tooltip: translate ( ' Control Actions ' ) ,
2022-08-28 16:55:16 +03:00
position: mod_menu . PopupMenuPosition . under ,
2022-09-08 10:35:19 +03:00
itemBuilder: ( BuildContext context ) = > _getControlMenu ( context )
2022-08-26 18:28:08 +03:00
. map ( ( entry ) = > entry . build (
context ,
2022-08-28 16:55:16 +03:00
const MenuConfig (
2022-08-26 18:28:08 +03:00
commonColor: _MenubarTheme . commonColor ,
2022-08-29 13:48:12 +03:00
height: _MenubarTheme . height ,
dividerHeight: _MenubarTheme . dividerHeight ,
2022-08-26 18:28:08 +03:00
) ) )
2022-08-30 12:20:25 +03:00
. expand ( ( i ) = > i )
2022-08-26 18:28:08 +03:00
. toList ( ) ,
) ;
}
Widget _buildDisplay ( BuildContext context ) {
2022-08-28 16:55:16 +03:00
return mod_menu . PopupMenuButton (
2022-08-26 18:28:08 +03:00
padding: EdgeInsets . zero ,
2022-08-28 16:55:16 +03:00
icon: const Icon (
2022-08-26 18:28:08 +03:00
Icons . tv ,
color: _MenubarTheme . commonColor ,
) ,
tooltip: translate ( ' Display Settings ' ) ,
2022-08-28 16:55:16 +03:00
position: mod_menu . PopupMenuPosition . under ,
2022-08-26 18:28:08 +03:00
itemBuilder: ( BuildContext context ) = > _getDisplayMenu ( )
. map ( ( entry ) = > entry . build (
context ,
2022-08-28 16:55:16 +03:00
const MenuConfig (
2022-08-26 18:28:08 +03:00
commonColor: _MenubarTheme . commonColor ,
2022-08-29 13:48:12 +03:00
height: _MenubarTheme . height ,
dividerHeight: _MenubarTheme . dividerHeight ,
2022-08-26 18:28:08 +03:00
) ) )
2022-08-30 12:20:25 +03:00
. expand ( ( i ) = > i )
2022-08-26 18:28:08 +03:00
. toList ( ) ,
) ;
}
2022-09-05 17:18:29 +03:00
Widget _buildKeyboard ( BuildContext context ) {
return mod_menu . PopupMenuButton (
padding: EdgeInsets . zero ,
icon: const Icon (
Icons . keyboard ,
color: _MenubarTheme . commonColor ,
) ,
tooltip: translate ( ' Keyboard Settings ' ) ,
position: mod_menu . PopupMenuPosition . under ,
itemBuilder: ( BuildContext context ) = > _getKeyboardMenu ( )
. map ( ( entry ) = > entry . build (
context ,
const MenuConfig (
commonColor: _MenubarTheme . commonColor ,
height: _MenubarTheme . height ,
dividerHeight: _MenubarTheme . dividerHeight ,
) ) )
. expand ( ( i ) = > i )
. toList ( ) ,
) ;
}
2022-08-26 18:28:08 +03:00
Widget _buildClose ( BuildContext context ) {
return IconButton (
tooltip: translate ( ' Close ' ) ,
onPressed: ( ) {
clientClose ( widget . ffi . dialogManager ) ;
} ,
2022-08-28 16:55:16 +03:00
icon: const Icon (
2022-08-26 18:28:08 +03:00
Icons . close ,
color: _MenubarTheme . commonColor ,
) ,
) ;
}
2022-09-08 10:35:19 +03:00
List < MenuEntryBase < String > > _getControlMenu ( BuildContext context ) {
2022-08-26 18:28:08 +03:00
final pi = widget . ffi . ffiModel . pi ;
final perms = widget . ffi . ffiModel . permissions ;
final List < MenuEntryBase < String > > displayMenu = [ ] ;
2022-09-08 10:35:19 +03:00
displayMenu . addAll ( [
MenuEntryButton < String > (
childBuilder: ( TextStyle ? style ) = > Row (
children: [
Text (
translate ( ' OS Password ' ) ,
style: style ,
) ,
Expanded (
child: Align (
alignment: Alignment . centerRight ,
child: IconButton (
padding: EdgeInsets . zero ,
icon: const Icon ( Icons . edit ) ,
onPressed: ( ) = > showSetOSPassword (
widget . id , false , widget . ffi . dialogManager ) ,
) ,
) )
] ,
) ,
proc: ( ) {
showSetOSPassword ( widget . id , false , widget . ffi . dialogManager ) ;
} ,
dismissOnClicked: true ,
) ,
MenuEntryButton < String > (
2022-08-26 18:28:08 +03:00
childBuilder: ( TextStyle ? style ) = > Text (
2022-09-08 10:35:19 +03:00
translate ( ' Transfer File ' ) ,
2022-08-26 18:28:08 +03:00
style: style ,
) ,
proc: ( ) {
2022-09-08 10:35:19 +03:00
connect ( context , widget . id , isFileTransfer: true ) ;
2022-08-26 18:28:08 +03:00
} ,
2022-08-31 13:41:55 +03:00
dismissOnClicked: true ,
2022-08-26 18:28:08 +03:00
) ,
2022-09-08 10:35:19 +03:00
MenuEntryButton < String > (
childBuilder: ( TextStyle ? style ) = > Text (
translate ( ' TCP Tunneling ' ) ,
style: style ,
) ,
proc: ( ) {
connect ( context , widget . id , isTcpTunneling: true ) ;
} ,
dismissOnClicked: true ,
) ,
] ) ;
// {handler.get_audit_server() && <li #note>{translate('Note')}</li>}
final auditServer = bind . sessionGetAuditServerSync ( id: widget . id ) ;
2022-09-08 18:25:19 +03:00
if ( auditServer . isNotEmpty ) {
displayMenu . add (
MenuEntryButton < String > (
childBuilder: ( TextStyle ? style ) = > Text (
translate ( ' Note ' ) ,
style: style ,
) ,
proc: ( ) {
showAuditDialog ( widget . id , widget . ffi . dialogManager ) ;
} ,
dismissOnClicked: true ,
2022-08-26 18:28:08 +03:00
) ,
2022-09-08 18:25:19 +03:00
) ;
}
2022-09-08 10:35:19 +03:00
displayMenu . add ( MenuEntryDivider ( ) ) ;
2022-08-26 18:28:08 +03:00
if ( perms [ ' keyboard ' ] ! = false ) {
if ( pi . platform = = ' Linux ' | | pi . sasEnabled ) {
displayMenu . add ( MenuEntryButton < String > (
childBuilder: ( TextStyle ? style ) = > Text (
2022-08-28 16:55:16 +03:00
' ${ translate ( " Insert " ) } Ctrl + Alt + Del ' ,
2022-08-26 18:28:08 +03:00
style: style ,
) ,
proc: ( ) {
bind . sessionCtrlAltDel ( id: widget . id ) ;
} ,
2022-08-31 13:41:55 +03:00
dismissOnClicked: true ,
2022-08-26 18:28:08 +03:00
) ) ;
}
2022-09-08 10:35:19 +03:00
}
if ( gFFI . ffiModel . permissions [ " restart " ] ! = false & &
( pi . platform = = " Linux " | |
pi . platform = = " Windows " | |
pi . platform = = " Mac OS " ) ) {
displayMenu . add ( MenuEntryButton < String > (
childBuilder: ( TextStyle ? style ) = > Text (
translate ( ' Restart Remote Device ' ) ,
style: style ,
) ,
proc: ( ) {
showRestartRemoteDevice ( pi , widget . id , gFFI . dialogManager ) ;
} ,
dismissOnClicked: true ,
) ) ;
}
2022-08-26 18:28:08 +03:00
2022-09-08 10:35:19 +03:00
if ( perms [ ' keyboard ' ] ! = false ) {
2022-08-26 18:28:08 +03:00
displayMenu . add ( MenuEntryButton < String > (
childBuilder: ( TextStyle ? style ) = > Text (
translate ( ' Insert Lock ' ) ,
style: style ,
) ,
proc: ( ) {
bind . sessionLockScreen ( id: widget . id ) ;
} ,
2022-08-31 13:41:55 +03:00
dismissOnClicked: true ,
2022-08-26 18:28:08 +03:00
) ) ;
if ( pi . platform = = ' Windows ' ) {
displayMenu . add ( MenuEntryButton < String > (
childBuilder: ( TextStyle ? style ) = > Obx ( ( ) = > Text (
translate (
2022-08-28 16:55:16 +03:00
' ${ BlockInputState . find ( widget . id ) . value ? " Unb " : " B " } lock user input ' ) ,
2022-08-26 18:28:08 +03:00
style: style ,
) ) ,
proc: ( ) {
RxBool blockInput = BlockInputState . find ( widget . id ) ;
bind . sessionToggleOption (
id: widget . id ,
2022-08-28 16:55:16 +03:00
value: ' ${ blockInput . value ? " un " : " " } block-input ' ) ;
2022-08-26 18:28:08 +03:00
blockInput . value = ! blockInput . value ;
} ,
2022-08-31 13:41:55 +03:00
dismissOnClicked: true ,
2022-08-26 18:28:08 +03:00
) ) ;
}
}
2022-09-08 10:35:19 +03:00
if ( pi . version . isNotEmpty ) {
2022-08-26 18:28:08 +03:00
displayMenu . add ( MenuEntryButton < String > (
childBuilder: ( TextStyle ? style ) = > Text (
2022-09-08 10:35:19 +03:00
translate ( ' Refresh ' ) ,
2022-08-26 18:28:08 +03:00
style: style ,
) ,
proc: ( ) {
2022-09-08 10:35:19 +03:00
bind . sessionRefresh ( id: widget . id ) ;
} ,
dismissOnClicked: true ,
) ) ;
}
if ( ! isWebDesktop ) {
// if (perms['keyboard'] != false && perms['clipboard'] != false) {
// displayMenu.add(MenuEntryButton<String>(
// childBuilder: (TextStyle? style) => Text(
// translate('Paste'),
// style: style,
// ),
// proc: () {
// () async {
// ClipboardData? data =
// await Clipboard.getData(Clipboard.kTextPlain);
// if (data != null && data.text != null) {
// bind.sessionInputString(id: widget.id, value: data.text ?? "");
// }
// }();
// },
// dismissOnClicked: true,
// ));
// }
displayMenu . add ( MenuEntryButton < String > (
childBuilder: ( TextStyle ? style ) = > Text (
translate ( ' Reset canvas ' ) ,
style: style ,
) ,
proc: ( ) {
widget . ffi . cursorModel . reset ( ) ;
2022-08-26 18:28:08 +03:00
} ,
2022-08-31 13:41:55 +03:00
dismissOnClicked: true ,
2022-08-26 18:28:08 +03:00
) ) ;
}
return displayMenu ;
}
List < MenuEntryBase < String > > _getDisplayMenu ( ) {
final displayMenu = [
2022-08-30 12:20:25 +03:00
MenuEntryRadios < String > (
2022-08-26 18:28:08 +03:00
text: translate ( ' Ratio ' ) ,
optionsGetter: ( ) = > [
2022-08-31 13:41:55 +03:00
MenuEntryRadioOption (
text: translate ( ' Scale original ' ) , value: ' original ' ) ,
MenuEntryRadioOption (
text: translate ( ' Scale adaptive ' ) , value: ' adaptive ' ) ,
2022-08-26 18:28:08 +03:00
] ,
curOptionGetter: ( ) async {
return await bind . sessionGetOption (
id: widget . id , arg: ' view-style ' ) ? ?
2022-08-31 11:41:05 +03:00
' adaptive ' ;
2022-08-26 18:28:08 +03:00
} ,
2022-08-31 13:41:55 +03:00
optionSetter: ( String oldValue , String newValue ) async {
2022-08-26 18:28:08 +03:00
await bind . sessionPeerOption (
2022-08-31 13:41:55 +03:00
id: widget . id , name: " view-style " , value: newValue ) ;
2022-08-26 18:28:08 +03:00
widget . ffi . canvasModel . updateViewStyle ( ) ;
} ) ,
2022-08-30 12:20:25 +03:00
MenuEntryDivider < String > ( ) ,
MenuEntryRadios < String > (
2022-08-26 18:28:08 +03:00
text: translate ( ' Scroll Style ' ) ,
optionsGetter: ( ) = > [
2022-08-31 13:41:55 +03:00
MenuEntryRadioOption (
text: translate ( ' ScrollAuto ' ) , value: ' scrollauto ' ) ,
MenuEntryRadioOption (
text: translate ( ' Scrollbar ' ) , value: ' scrollbar ' ) ,
2022-08-26 18:28:08 +03:00
] ,
curOptionGetter: ( ) async {
return await bind . sessionGetOption (
id: widget . id , arg: ' scroll-style ' ) ? ?
' ' ;
} ,
2022-08-31 13:41:55 +03:00
optionSetter: ( String oldValue , String newValue ) async {
2022-08-26 18:28:08 +03:00
await bind . sessionPeerOption (
2022-08-31 13:41:55 +03:00
id: widget . id , name: " scroll-style " , value: newValue ) ;
2022-08-26 18:28:08 +03:00
widget . ffi . canvasModel . updateScrollStyle ( ) ;
} ) ,
2022-08-30 12:20:25 +03:00
MenuEntryDivider < String > ( ) ,
MenuEntryRadios < String > (
2022-08-26 18:28:08 +03:00
text: translate ( ' Image Quality ' ) ,
optionsGetter: ( ) = > [
2022-08-31 13:41:55 +03:00
MenuEntryRadioOption (
text: translate ( ' Good image quality ' ) , value: ' best ' ) ,
MenuEntryRadioOption (
text: translate ( ' Balanced ' ) , value: ' balanced ' ) ,
MenuEntryRadioOption (
text: translate ( ' Optimize reaction time ' ) , value: ' low ' ) ,
MenuEntryRadioOption (
text: translate ( ' Custom ' ) ,
value: ' custom ' ,
dismissOnClicked: true ) ,
2022-08-26 18:28:08 +03:00
] ,
curOptionGetter: ( ) async {
String quality =
await bind . sessionGetImageQuality ( id: widget . id ) ? ? ' balanced ' ;
if ( quality = = ' ' ) quality = ' balanced ' ;
return quality ;
} ,
2022-08-31 13:41:55 +03:00
optionSetter: ( String oldValue , String newValue ) async {
if ( oldValue ! = newValue ) {
await bind . sessionSetImageQuality ( id: widget . id , value: newValue ) ;
}
if ( newValue = = ' custom ' ) {
2022-09-01 09:02:02 +03:00
final btnCancel = msgBoxButton ( translate ( ' Close ' ) , ( ) {
2022-08-31 13:41:55 +03:00
widget . ffi . dialogManager . dismissAll ( ) ;
} ) ;
final quality =
await bind . sessionGetCustomImageQuality ( id: widget . id ) ;
2022-09-02 08:36:40 +03:00
double initValue = quality ! = null & & quality . isNotEmpty
2022-08-31 13:41:55 +03:00
? quality [ 0 ] . toDouble ( )
: 50.0 ;
2022-09-02 08:36:40 +03:00
const minValue = 10.0 ;
const maxValue = 100.0 ;
if ( initValue < minValue ) {
initValue = minValue ;
}
if ( initValue > maxValue ) {
initValue = maxValue ;
}
2022-08-31 13:41:55 +03:00
final RxDouble sliderValue = RxDouble ( initValue ) ;
2022-09-01 09:02:02 +03:00
final rxReplay = rxdart . ReplaySubject < double > ( ) ;
rxReplay
. throttleTime ( const Duration ( milliseconds: 1000 ) ,
trailing: true , leading: false )
. listen ( ( double v ) {
( ) async {
await bind . sessionSetCustomImageQuality (
id: widget . id , value: v . toInt ( ) ) ;
} ( ) ;
} ) ;
final slider = Obx ( ( ) {
return Slider (
value: sliderValue . value ,
2022-09-02 08:36:40 +03:00
min: minValue ,
max: maxValue ,
2022-09-02 05:39:51 +03:00
divisions: 90 ,
2022-09-01 09:02:02 +03:00
onChanged: ( double value ) {
sliderValue . value = value ;
rxReplay . add ( value ) ;
} ,
) ;
} ) ;
2022-09-02 05:39:51 +03:00
final content = Row (
children: [
slider ,
2022-09-02 08:36:40 +03:00
SizedBox (
width: 90 ,
child: Obx ( ( ) = > Text (
' ${ sliderValue . value . round ( ) } % Bitrate ' ,
style: const TextStyle ( fontSize: 15 ) ,
) ) )
2022-09-02 05:39:51 +03:00
] ,
) ;
2022-08-31 13:41:55 +03:00
msgBoxCommon ( widget . ffi . dialogManager , ' Custom Image Quality ' ,
2022-09-02 05:39:51 +03:00
content , [ btnCancel ] ) ;
2022-08-31 13:41:55 +03:00
}
2022-08-26 18:28:08 +03:00
} ) ,
2022-08-30 12:20:25 +03:00
MenuEntryDivider < String > ( ) ,
2022-09-08 18:25:19 +03:00
// {show_codec ? <div>
// MenuEntryDivider<String>(),
2022-09-03 05:39:33 +03:00
( ) {
final state = ShowRemoteCursorState . find ( widget . id ) ;
return MenuEntrySwitch2 < String > (
text: translate ( ' Show remote cursor ' ) ,
getter: ( ) {
return state ;
} ,
setter: ( bool v ) async {
state . value = v ;
await bind . sessionToggleOption (
id: widget . id , value: ' show-remote-cursor ' ) ;
} ) ;
} ( ) ,
2022-08-26 18:28:08 +03:00
MenuEntrySwitch < String > (
text: translate ( ' Show quality monitor ' ) ,
getter: ( ) async {
2022-08-28 16:55:16 +03:00
return bind . sessionGetToggleOptionSync (
2022-08-26 18:28:08 +03:00
id: widget . id , arg: ' show-quality-monitor ' ) ;
} ,
setter: ( bool v ) async {
await bind . sessionToggleOption (
id: widget . id , value: ' show-quality-monitor ' ) ;
widget . ffi . qualityMonitorModel . checkShowQualityMonitor ( widget . id ) ;
} ) ,
] ;
final perms = widget . ffi . ffiModel . permissions ;
final pi = widget . ffi . ffiModel . pi ;
if ( perms [ ' audio ' ] ! = false ) {
displayMenu . add ( _createSwitchMenuEntry ( ' Mute ' , ' disable-audio ' ) ) ;
}
2022-09-08 18:25:19 +03:00
if ( Platform . isWindows & &
pi . platform = = ' Windows ' & &
perms [ ' file ' ] ! = false ) {
displayMenu . add ( _createSwitchMenuEntry (
' Allow file copy and paste ' , ' enable-file-transfer ' ) ) ;
}
2022-08-26 18:28:08 +03:00
if ( perms [ ' keyboard ' ] ! = false ) {
if ( perms [ ' clipboard ' ] ! = false ) {
displayMenu . add (
_createSwitchMenuEntry ( ' Disable clipboard ' , ' disable-clipboard ' ) ) ;
}
displayMenu . add ( _createSwitchMenuEntry (
' Lock after session end ' , ' lock-after-session-end ' ) ) ;
if ( pi . platform = = ' Windows ' ) {
displayMenu . add ( MenuEntrySwitch2 < String > (
2022-09-03 05:39:33 +03:00
dismissOnClicked: true ,
2022-08-26 18:28:08 +03:00
text: translate ( ' Privacy mode ' ) ,
getter: ( ) {
return PrivacyModeState . find ( widget . id ) ;
} ,
setter: ( bool v ) async {
await bind . sessionToggleOption (
id: widget . id , value: ' privacy-mode ' ) ;
} ) ) ;
}
}
return displayMenu ;
}
2022-09-05 17:18:29 +03:00
List < MenuEntryBase < String > > _getKeyboardMenu ( ) {
final keyboardMenu = [
MenuEntryRadios < String > (
text: translate ( ' Ratio ' ) ,
optionsGetter: ( ) = > [
MenuEntryRadioOption (
text: translate ( ' Legacy mode ' ) , value: ' legacy ' ) ,
MenuEntryRadioOption ( text: translate ( ' Map mode ' ) , value: ' map ' ) ,
] ,
curOptionGetter: ( ) async {
2022-09-08 04:39:45 +03:00
return await bind . sessionGetKeyboardName ( id: widget . id ) ;
2022-09-05 17:18:29 +03:00
} ,
optionSetter: ( String oldValue , String newValue ) async {
await bind . sessionSetKeyboardMode (
id: widget . id , keyboardMode: newValue ) ;
widget . ffi . canvasModel . updateViewStyle ( ) ;
} )
] ;
return keyboardMenu ;
}
2022-08-26 18:28:08 +03:00
MenuEntrySwitch < String > _createSwitchMenuEntry ( String text , String option ) {
return MenuEntrySwitch < String > (
text: translate ( text ) ,
getter: ( ) async {
return bind . sessionGetToggleOptionSync ( id: widget . id , arg: option ) ;
} ,
setter: ( bool v ) async {
await bind . sessionToggleOption ( id: widget . id , value: option ) ;
} ) ;
}
}
void showSetOSPassword (
String id , bool login , OverlayDialogManager dialogManager ) async {
final controller = TextEditingController ( ) ;
var password = await bind . sessionGetOption ( id: id , arg: " os-password " ) ? ? " " ;
var autoLogin = await bind . sessionGetOption ( id: id , arg: " auto-login " ) ! = " " ;
controller . text = password ;
dialogManager . show ( ( setState , close ) {
2022-09-03 13:19:50 +03:00
submit ( ) {
var text = controller . text . trim ( ) ;
bind . sessionPeerOption ( id: id , name: " os-password " , value: text ) ;
bind . sessionPeerOption (
id: id , name: " auto-login " , value: autoLogin ? ' Y ' : ' ' ) ;
if ( text ! = " " & & login ) {
bind . sessionInputOsPassword ( id: id , value: text ) ;
}
close ( ) ;
}
2022-08-26 18:28:08 +03:00
return CustomAlertDialog (
2022-09-03 13:19:50 +03:00
title: Text ( translate ( ' OS Password ' ) ) ,
content: Column ( mainAxisSize: MainAxisSize . min , children: [
PasswordWidget ( controller: controller ) ,
CheckboxListTile (
contentPadding: const EdgeInsets . all ( 0 ) ,
dense: true ,
controlAffinity: ListTileControlAffinity . leading ,
title: Text (
translate ( ' Auto Login ' ) ,
2022-08-26 18:28:08 +03:00
) ,
2022-09-03 13:19:50 +03:00
value: autoLogin ,
onChanged: ( v ) {
if ( v = = null ) return ;
setState ( ( ) = > autoLogin = v ) ;
} ,
) ,
] ) ,
actions: [
TextButton (
style: flatButtonStyle ,
onPressed: close ,
child: Text ( translate ( ' Cancel ' ) ) ,
) ,
TextButton (
style: flatButtonStyle ,
onPressed: submit ,
child: Text ( translate ( ' OK ' ) ) ,
) ,
] ,
onSubmit: submit ,
onCancel: close ,
) ;
2022-08-26 18:28:08 +03:00
} ) ;
}
2022-09-08 10:35:19 +03:00
void showAuditDialog ( String id , dialogManager ) async {
final controller = TextEditingController ( ) ;
dialogManager . show ( ( setState , close ) {
submit ( ) {
var text = controller . text . trim ( ) ;
if ( text ! = " " ) {
bind . sessionSendNote ( id: id , note: text ) ;
}
close ( ) ;
}
late final focusNode = FocusNode (
onKey: ( FocusNode node , RawKeyEvent evt ) {
if ( evt . logicalKey . keyLabel = = ' Enter ' ) {
if ( evt is RawKeyDownEvent ) {
int pos = controller . selection . base . offset ;
controller . text =
' ${ controller . text . substring ( 0 , pos ) } \n ${ controller . text . substring ( pos ) } ' ;
controller . selection =
TextSelection . fromPosition ( TextPosition ( offset: pos + 1 ) ) ;
}
return KeyEventResult . handled ;
}
if ( evt . logicalKey . keyLabel = = ' Esc ' ) {
if ( evt is RawKeyDownEvent ) {
close ( ) ;
}
return KeyEventResult . handled ;
} else {
return KeyEventResult . ignored ;
}
} ,
) ;
return CustomAlertDialog (
title: Text ( translate ( ' Note ' ) ) ,
content: SizedBox (
width: 250 ,
height: 120 ,
child: TextField (
autofocus: true ,
keyboardType: TextInputType . multiline ,
textInputAction: TextInputAction . newline ,
decoration: const InputDecoration . collapsed (
hintText: " input note here " ,
) ,
// inputFormatters: [
// LengthLimitingTextInputFormatter(16),
// // FilteringTextInputFormatter(RegExp(r"[a-zA-z][a-zA-z0-9\_]*"), allow: true)
// ],
maxLines: null ,
maxLength: 256 ,
controller: controller ,
focusNode: focusNode ,
) ) ,
actions: [
TextButton (
style: flatButtonStyle ,
onPressed: close ,
child: Text ( translate ( ' Cancel ' ) ) ,
) ,
TextButton (
style: flatButtonStyle ,
onPressed: submit ,
child: Text ( translate ( ' OK ' ) ) ,
) ,
] ,
onSubmit: submit ,
onCancel: close ,
) ;
} ) ;
}