2022-12-16 22:15:26 +08:00
import ' dart:async ' ;
2022-01-23 21:37:19 +08:00
import ' package:flutter/material.dart ' ;
2023-03-09 23:40:30 +08:00
import ' package:flutter/services.dart ' ;
2022-05-24 23:33:00 +08:00
import ' package:flutter_hbb/mobile/widgets/dialog.dart ' ;
2023-07-09 19:14:57 +08:00
import ' package:flutter_hbb/models/chat_model.dart ' ;
2023-03-01 15:55:21 +08:00
import ' package:get/get.dart ' ;
2022-02-02 17:25:56 +08:00
import ' package:provider/provider.dart ' ;
2022-01-23 21:37:19 +08:00
2022-05-24 23:33:00 +08:00
import ' ../../common.dart ' ;
2022-09-16 21:52:08 +08:00
import ' ../../common/widgets/dialog.dart ' ;
2023-03-02 01:00:56 +08:00
import ' ../../consts.dart ' ;
2022-08-08 22:27:27 +08:00
import ' ../../models/platform_model.dart ' ;
2022-05-24 23:33:00 +08:00
import ' ../../models/server_model.dart ' ;
2022-02-28 18:29:25 +08:00
import ' home_page.dart ' ;
2022-08-09 20:36:52 +08:00
class ServerPage extends StatefulWidget implements PageShape {
2022-02-28 18:29:25 +08:00
@ override
2022-03-23 15:28:21 +08:00
final title = translate ( " Share Screen " ) ;
2022-02-28 18:29:25 +08:00
@ override
2022-09-16 20:43:15 +08:00
final icon = const Icon ( Icons . mobile_screen_share ) ;
2022-02-28 18:29:25 +08:00
@ override
final appBarActions = [
2022-04-04 01:38:53 +08:00
PopupMenuButton < String > (
2023-06-29 10:26:03 +08:00
tooltip: " " ,
2022-09-16 20:43:15 +08:00
icon: const Icon ( Icons . more_vert ) ,
2022-04-04 01:38:53 +08:00
itemBuilder: ( context ) {
2023-06-28 20:22:57 +08:00
listTile ( String text , bool checked ) {
return ListTile (
title: Text ( translate ( text ) ) ,
trailing: Icon (
Icons . check ,
color: checked ? null : Colors . transparent ,
) ) ;
}
final approveMode = gFFI . serverModel . approveMode ;
final verificationMethod = gFFI . serverModel . verificationMethod ;
final showPasswordOption = approveMode ! = ' click ' ;
2022-04-04 01:38:53 +08:00
return [
PopupMenuItem (
2023-06-26 23:27:18 +08:00
enabled: gFFI . serverModel . connectStatus > 0 ,
2022-09-16 20:43:15 +08:00
padding: const EdgeInsets . symmetric ( horizontal: 16.0 ) ,
2022-04-04 01:38:53 +08:00
value: " changeID " ,
2022-09-16 20:43:15 +08:00
child: Text ( translate ( " Change ID " ) ) ,
2022-04-04 01:38:53 +08:00
) ,
2022-07-29 18:34:25 +08:00
const PopupMenuDivider ( ) ,
2022-04-04 01:38:53 +08:00
PopupMenuItem (
2022-09-16 20:43:15 +08:00
padding: const EdgeInsets . symmetric ( horizontal: 0.0 ) ,
2023-06-28 20:22:57 +08:00
value: ' AcceptSessionsViaPassword ' ,
child: listTile (
' Accept sessions via password ' , approveMode = = ' password ' ) ,
2022-07-29 18:34:25 +08:00
) ,
2022-07-29 22:07:45 +08:00
PopupMenuItem (
2022-09-16 20:43:15 +08:00
padding: const EdgeInsets . symmetric ( horizontal: 0.0 ) ,
2023-06-28 20:22:57 +08:00
value: ' AcceptSessionsViaClick ' ,
child:
listTile ( ' Accept sessions via click ' , approveMode = = ' click ' ) ,
2022-07-29 18:34:25 +08:00
) ,
2022-07-29 22:07:45 +08:00
PopupMenuItem (
2022-09-16 20:43:15 +08:00
padding: const EdgeInsets . symmetric ( horizontal: 0.0 ) ,
2023-06-28 20:22:57 +08:00
value: " AcceptSessionsViaBoth " ,
child: listTile ( " Accept sessions via both " ,
approveMode ! = ' password ' & & approveMode ! = ' click ' ) ,
2022-07-29 18:34:25 +08:00
) ,
2023-06-28 20:22:57 +08:00
if ( showPasswordOption ) const PopupMenuDivider ( ) ,
if ( showPasswordOption & &
verificationMethod ! = kUseTemporaryPassword )
PopupMenuItem (
padding: const EdgeInsets . symmetric ( horizontal: 16.0 ) ,
value: " setPermanentPassword " ,
child: Text ( translate ( " Set permanent password " ) ) ,
) ,
if ( showPasswordOption & &
verificationMethod ! = kUsePermanentPassword )
PopupMenuItem (
padding: const EdgeInsets . symmetric ( horizontal: 16.0 ) ,
value: " setTemporaryPasswordLength " ,
child: Text ( translate ( " One-time password length " ) ) ,
) ,
if ( showPasswordOption ) const PopupMenuDivider ( ) ,
if ( showPasswordOption )
PopupMenuItem (
padding: const EdgeInsets . symmetric ( horizontal: 0.0 ) ,
value: kUseTemporaryPassword ,
child: listTile ( ' Use one-time password ' ,
verificationMethod = = kUseTemporaryPassword ) ,
) ,
if ( showPasswordOption )
PopupMenuItem (
padding: const EdgeInsets . symmetric ( horizontal: 0.0 ) ,
value: kUsePermanentPassword ,
child: listTile ( ' Use permanent password ' ,
verificationMethod = = kUsePermanentPassword ) ,
) ,
if ( showPasswordOption )
PopupMenuItem (
padding: const EdgeInsets . symmetric ( horizontal: 0.0 ) ,
value: kUseBothPasswords ,
child: listTile (
' Use both passwords ' ,
verificationMethod ! = kUseTemporaryPassword & &
verificationMethod ! = kUsePermanentPassword ) ,
) ,
2022-04-04 01:38:53 +08:00
] ;
} ,
onSelected: ( value ) {
if ( value = = " changeID " ) {
2022-09-16 21:52:08 +08:00
changeIdDialog ( ) ;
2022-07-29 18:34:25 +08:00
} else if ( value = = " setPermanentPassword " ) {
2022-08-12 18:42:02 +08:00
setPermanentPasswordDialog ( gFFI . dialogManager ) ;
2022-07-29 18:34:25 +08:00
} else if ( value = = " setTemporaryPasswordLength " ) {
2022-08-12 18:42:02 +08:00
setTemporaryPasswordLengthDialog ( gFFI . dialogManager ) ;
2022-07-29 18:34:25 +08:00
} else if ( value = = kUsePermanentPassword | |
value = = kUseTemporaryPassword | |
value = = kUseBothPasswords ) {
2022-08-08 22:27:27 +08:00
bind . mainSetOption ( key: " verification-method " , value: value ) ;
2022-08-01 10:44:05 +08:00
gFFI . serverModel . updatePasswordModel ( ) ;
2023-06-28 20:22:57 +08:00
} else if ( value . startsWith ( " AcceptSessionsVia " ) ) {
value = value . substring ( " AcceptSessionsVia " . length ) ;
if ( value = = " Password " ) {
gFFI . serverModel . setApproveMode ( ' password ' ) ;
} else if ( value = = " Click " ) {
gFFI . serverModel . setApproveMode ( ' click ' ) ;
} else {
gFFI . serverModel . setApproveMode ( ' ' ) ;
}
2022-03-30 23:09:19 +08:00
}
2022-04-04 01:38:53 +08:00
} )
2022-02-28 18:29:25 +08:00
] ;
2022-01-23 21:37:19 +08:00
2022-09-16 20:43:15 +08:00
ServerPage ( { Key ? key } ) : super ( key: key ) ;
2022-08-09 20:36:52 +08:00
@ override
State < StatefulWidget > createState ( ) = > _ServerPageState ( ) ;
}
class _ServerPageState extends State < ServerPage > {
2022-12-16 22:15:26 +08:00
Timer ? _updateTimer ;
2022-08-09 20:36:52 +08:00
@ override
void initState ( ) {
super . initState ( ) ;
2022-12-16 22:15:26 +08:00
_updateTimer = periodic_immediate ( const Duration ( seconds: 3 ) , ( ) async {
await gFFI . serverModel . fetchID ( ) ;
} ) ;
2022-08-09 20:36:52 +08:00
gFFI . serverModel . checkAndroidPermission ( ) ;
}
2022-12-16 22:15:26 +08:00
@ override
void dispose ( ) {
_updateTimer ? . cancel ( ) ;
super . dispose ( ) ;
}
2022-01-23 21:37:19 +08:00
@ override
Widget build ( BuildContext context ) {
2022-02-08 22:45:48 +08:00
checkService ( ) ;
2022-03-25 16:34:27 +08:00
return ChangeNotifierProvider . value (
2022-06-13 21:07:26 +08:00
value: gFFI . serverModel ,
2022-03-25 16:34:27 +08:00
child: Consumer < ServerModel > (
builder: ( context , serverModel , child ) = > SingleChildScrollView (
2022-06-13 21:07:26 +08:00
controller: gFFI . serverModel . controller ,
2022-03-25 16:34:27 +08:00
child: Center (
child: Column (
mainAxisAlignment: MainAxisAlignment . start ,
children: [
2023-03-06 22:27:22 +08:00
gFFI . serverModel . isStart
? ServerInfo ( )
: ServiceNotRunningNotification ( ) ,
2022-09-16 20:43:15 +08:00
const ConnectionManager ( ) ,
2023-03-02 21:56:51 +08:00
const PermissionChecker ( ) ,
2022-09-16 20:43:15 +08:00
SizedBox . fromSize ( size: const Size ( 0 , 15.0 ) ) ,
2022-03-25 16:34:27 +08:00
] ,
) ,
) ,
) ) ) ;
2022-01-23 21:37:19 +08:00
}
}
2022-04-04 14:54:00 +08:00
void checkService ( ) async {
2023-03-02 01:00:56 +08:00
gFFI . invokeMethod ( " check_service " ) ;
// for Android 10/11, request MANAGE_EXTERNAL_STORAGE permission from system setting page
if ( AndroidPermissionManager . isWaitingFile ( ) & & ! gFFI . serverModel . fileOk ) {
AndroidPermissionManager . complete ( kManageExternalStorage ,
await AndroidPermissionManager . check ( kManageExternalStorage ) ) ;
2022-04-04 14:54:00 +08:00
debugPrint ( " file permission finished " ) ;
}
2022-02-08 22:45:48 +08:00
}
2023-03-06 22:27:22 +08:00
class ServiceNotRunningNotification extends StatelessWidget {
ServiceNotRunningNotification ( { Key ? key } ) : super ( key: key ) ;
@ override
Widget build ( BuildContext context ) {
final serverModel = Provider . of < ServerModel > ( context ) ;
return PaddingCard (
2023-03-07 18:45:20 +08:00
title: translate ( " Service is not running " ) ,
titleIcon:
const Icon ( Icons . warning_amber_sharp , color: Colors . redAccent ) ,
2023-03-06 22:27:22 +08:00
child: Column (
2023-03-07 18:45:20 +08:00
crossAxisAlignment: CrossAxisAlignment . start ,
2023-03-06 22:27:22 +08:00
children: [
2023-03-07 18:45:20 +08:00
Text ( translate ( " android_start_service_tip " ) ,
style:
const TextStyle ( fontSize: 12 , color: MyTheme . darkGray ) )
. marginOnly ( bottom: 8 ) ,
ElevatedButton . icon (
icon: const Icon ( Icons . play_arrow ) ,
2023-09-12 00:18:36 +08:00
onPressed: ( ) {
if ( gFFI . userModel . userName . value . isEmpty & & bind . mainGetLocalOption ( key: " show-scam-warning " ) ! = " N " ) {
_showScamWarning ( context , serverModel ) ;
} else {
serverModel . toggleService ( ) ;
}
} ,
2023-03-07 18:45:20 +08:00
label: Text ( translate ( " Start Service " ) ) )
2023-03-06 22:27:22 +08:00
] ,
2023-03-07 18:45:20 +08:00
) ) ;
2023-03-06 22:27:22 +08:00
}
2023-09-12 00:18:36 +08:00
void _showScamWarning ( BuildContext context , ServerModel serverModel ) {
showDialog (
context: context ,
builder: ( BuildContext context ) {
return ScamWarningDialog ( serverModel: serverModel ) ;
} ,
) ;
}
}
class ScamWarningDialog extends StatefulWidget {
final ServerModel serverModel ;
ScamWarningDialog ( { required this . serverModel } ) ;
@ override
_ScamWarningDialogState createState ( ) = > _ScamWarningDialogState ( ) ;
}
class _ScamWarningDialogState extends State < ScamWarningDialog > {
int _countdown = 6 ;
bool show_warning = false ;
late Timer _timer ;
late ServerModel _serverModel ;
@ override
void initState ( ) {
super . initState ( ) ;
_serverModel = widget . serverModel ;
startCountdown ( ) ;
}
void startCountdown ( ) {
const oneSecond = Duration ( seconds: 1 ) ;
_timer = Timer . periodic ( oneSecond , ( timer ) {
setState ( ( ) {
_countdown - - ;
if ( _countdown < = 0 ) {
timer . cancel ( ) ;
}
} ) ;
} ) ;
}
@ override
void dispose ( ) {
_timer . cancel ( ) ;
super . dispose ( ) ;
}
@ override
Widget build ( BuildContext context ) {
final isButtonLocked = _countdown > 0 ;
return AlertDialog (
content: Container (
decoration: BoxDecoration (
gradient: LinearGradient (
begin: Alignment . topRight ,
end: Alignment . bottomLeft ,
colors: [
Color ( 0xffe242bc ) ,
Color ( 0xfff4727c ) ,
] ,
) ,
borderRadius: BorderRadius . circular ( 20.0 ) ,
) ,
padding: EdgeInsets . all ( 25.0 ) ,
child: Column (
mainAxisSize: MainAxisSize . min ,
crossAxisAlignment: CrossAxisAlignment . start ,
children: [
Row (
children: [
Icon (
Icons . warning_amber_sharp ,
color: Colors . white ,
) ,
SizedBox ( width: 10 ) ,
Text (
translate ( " Warning " ) ,
style: TextStyle (
color: Colors . white ,
fontWeight: FontWeight . bold ,
fontSize: 20.0 ,
) ,
) ,
] ,
) ,
SizedBox ( height: 20 ) ,
Center (
child: Image . asset ( ' assets/scam.png ' ,
width: 180 ,
) ,
) ,
SizedBox ( height: 18 ) ,
Text (
translate ( " You May Be Being SCAMMED! " ) ,
textAlign: TextAlign . center ,
style: TextStyle (
color: Colors . white ,
fontWeight: FontWeight . bold ,
fontSize: 22.0 ,
) ,
) ,
SizedBox ( height: 18 ) ,
Text (
translate ( " If you are on the phone with someone you DON'T know AND TRUST who has asked you to use RustDesk and start the service, do not proceed and hang up immediately. " ) + " \n \n "
+ translate ( " They are likely a scammer trying to steal your money or other private information. " ) + " \n " ,
style: TextStyle (
color: Colors . white ,
fontWeight: FontWeight . bold ,
fontSize: 16.0 ,
) ,
) ,
Row (
children: < Widget > [
Checkbox (
value: show_warning ,
onChanged: ( value ) {
setState ( ( ) {
show_warning = value ! ;
} ) ;
} ,
) ,
Text (
translate ( " Don't show again " ) ,
style: TextStyle (
color: Colors . white ,
fontWeight: FontWeight . bold ,
fontSize: 15.0 ,
) ,
) ,
] ,
) ,
SizedBox ( height: 10 ) ,
Row (
mainAxisAlignment: MainAxisAlignment . end ,
children: [
ElevatedButton (
onPressed: isButtonLocked
? null
: ( ) {
Navigator . of ( context ) . pop ( ) ;
_serverModel . toggleService ( ) ;
if ( show_warning ) {
bind . mainSetLocalOption ( key: " show-scam-warning " , value: " N " ) ;
}
} ,
style: ElevatedButton . styleFrom (
primary: Colors . blueAccent ,
) ,
child: Text (
isButtonLocked ? translate ( " I Agree " ) + " ( ${ _countdown } s) " : translate ( " I Agree " ) ,
style: TextStyle (
fontWeight: FontWeight . bold ,
fontSize: 13.0 ,
) ,
) ,
) ,
SizedBox ( width: 15 ) ,
ElevatedButton (
onPressed: ( ) {
Navigator . of ( context ) . pop ( ) ;
} ,
style: ElevatedButton . styleFrom (
primary: Colors . blueAccent ,
) ,
child: Text (
translate ( " Decline " ) ,
style: TextStyle (
fontWeight: FontWeight . bold ,
fontSize: 13.0 ,
) ,
) ,
) ,
] ,
) ] ) ) ,
contentPadding: EdgeInsets . all ( 0.0 ) ,
) ;
}
2023-03-06 22:27:22 +08:00
}
2022-07-29 18:34:25 +08:00
class ServerInfo extends StatelessWidget {
2022-06-13 21:07:26 +08:00
final model = gFFI . serverModel ;
2022-07-29 18:34:25 +08:00
final emptyController = TextEditingController ( text: " - " ) ;
2022-03-19 23:28:29 +08:00
2022-09-16 20:43:15 +08:00
ServerInfo ( { Key ? key } ) : super ( key: key ) ;
2022-01-23 21:37:19 +08:00
@ override
Widget build ( BuildContext context ) {
2022-07-29 18:34:25 +08:00
final isPermanent = model . verificationMethod = = kUsePermanentPassword ;
2023-06-23 18:25:42 +08:00
final serverModel = Provider . of < ServerModel > ( context ) ;
2023-03-02 10:05:03 +08:00
2023-03-10 00:25:29 +08:00
const Color colorPositive = Colors . green ;
const Color colorNegative = Colors . red ;
const double iconMarginRight = 15 ;
const double iconSize = 24 ;
const TextStyle textStyleHeading = TextStyle (
fontSize: 16.0 , fontWeight: FontWeight . bold , color: Colors . grey ) ;
const TextStyle textStyleValue =
TextStyle ( fontSize: 25.0 , fontWeight: FontWeight . bold ) ;
void copyToClipboard ( String value ) {
Clipboard . setData ( ClipboardData ( text: value ) ) ;
showToast ( translate ( ' Copied ' ) ) ;
}
2023-03-02 10:05:03 +08:00
2023-06-23 18:25:42 +08:00
Widget ConnectionStateNotification ( ) {
if ( serverModel . connectStatus = = - 1 ) {
return Row ( children: [
const Icon ( Icons . warning_amber_sharp ,
color: colorNegative , size: iconSize )
. marginOnly ( right: iconMarginRight ) ,
Expanded ( child: Text ( translate ( ' not_ready_status ' ) ) )
] ) ;
} else if ( serverModel . connectStatus = = 0 ) {
return Row ( children: [
SizedBox ( width: 20 , height: 20 , child: CircularProgressIndicator ( ) )
. marginOnly ( left: 4 , right: iconMarginRight ) ,
Expanded ( child: Text ( translate ( ' connecting_status ' ) ) )
] ) ;
} else {
return Row ( children: [
const Icon ( Icons . check , color: colorPositive , size: iconSize )
. marginOnly ( right: iconMarginRight ) ,
Expanded ( child: Text ( translate ( ' Ready ' ) ) )
] ) ;
}
}
2023-03-02 10:05:03 +08:00
2023-03-06 22:27:22 +08:00
return PaddingCard (
2023-03-09 23:40:30 +08:00
title: translate ( ' Your Device ' ) ,
2023-03-06 22:27:22 +08:00
child: Column (
2023-03-09 23:40:30 +08:00
// ID
children: [
Row ( children: [
2023-03-10 00:25:29 +08:00
const Icon ( Icons . perm_identity ,
color: Colors . grey , size: iconSize )
. marginOnly ( right: iconMarginRight ) ,
2023-03-09 23:40:30 +08:00
Text (
translate ( ' ID ' ) ,
2023-03-10 00:25:29 +08:00
style: textStyleHeading ,
2023-03-09 23:40:30 +08:00
)
] ) ,
Row ( mainAxisAlignment: MainAxisAlignment . spaceBetween , children: [
Text (
model . serverId . value . text ,
2023-03-10 00:25:29 +08:00
style: textStyleValue ,
2023-03-09 23:40:30 +08:00
) ,
IconButton (
visualDensity: VisualDensity . compact ,
icon: Icon ( Icons . copy_outlined ) ,
onPressed: ( ) {
2023-03-10 00:25:29 +08:00
copyToClipboard ( model . serverId . value . text . trim ( ) ) ;
2023-03-09 23:40:30 +08:00
} )
2023-03-10 00:25:29 +08:00
] ) . marginOnly ( left: 39 , bottom: 10 ) ,
2023-03-09 23:40:30 +08:00
// Password
Row ( children: [
2023-03-10 00:25:29 +08:00
const Icon ( Icons . lock_outline , color: Colors . grey , size: iconSize )
. marginOnly ( right: iconMarginRight ) ,
2023-03-09 23:40:30 +08:00
Text (
translate ( ' One-time Password ' ) ,
2023-03-10 00:25:29 +08:00
style: textStyleHeading ,
2023-03-09 23:40:30 +08:00
)
] ) ,
Row ( mainAxisAlignment: MainAxisAlignment . spaceBetween , children: [
Text (
isPermanent ? ' - ' : model . serverPasswd . value . text ,
2023-03-10 00:25:29 +08:00
style: textStyleValue ,
2022-03-22 16:40:23 +08:00
) ,
2023-03-09 23:40:30 +08:00
isPermanent
? SizedBox . shrink ( )
: Row ( children: [
IconButton (
visualDensity: VisualDensity . compact ,
icon: const Icon ( Icons . refresh ) ,
onPressed: ( ) = > bind . mainUpdateTemporaryPassword ( ) ) ,
IconButton (
visualDensity: VisualDensity . compact ,
icon: Icon ( Icons . copy_outlined ) ,
onPressed: ( ) {
2023-03-10 00:25:29 +08:00
copyToClipboard (
model . serverPasswd . value . text . trim ( ) ) ;
2023-03-09 23:40:30 +08:00
} )
] )
2023-03-10 00:25:29 +08:00
] ) . marginOnly ( left: 40 , bottom: 15 ) ,
2023-03-09 23:40:30 +08:00
ConnectionStateNotification ( )
] ,
) ) ;
2022-02-09 17:04:13 +08:00
}
2022-01-23 21:37:19 +08:00
}
class PermissionChecker extends StatefulWidget {
2022-09-16 20:43:15 +08:00
const PermissionChecker ( { Key ? key } ) : super ( key: key ) ;
2022-01-23 21:37:19 +08:00
@ override
2022-09-16 20:43:15 +08:00
State < PermissionChecker > createState ( ) = > _PermissionCheckerState ( ) ;
2022-01-23 21:37:19 +08:00
}
class _PermissionCheckerState extends State < PermissionChecker > {
@ override
Widget build ( BuildContext context ) {
2022-02-02 17:25:56 +08:00
final serverModel = Provider . of < ServerModel > ( context ) ;
2022-03-25 16:34:27 +08:00
final hasAudioPermission = androidVersion > = 30 ;
2022-03-22 16:40:23 +08:00
return PaddingCard (
2022-04-20 15:45:51 +08:00
title: translate ( " Permissions " ) ,
2023-03-01 15:55:21 +08:00
child: Column ( crossAxisAlignment: CrossAxisAlignment . start , children: [
2023-03-02 10:05:03 +08:00
serverModel . mediaOk
? ElevatedButton . icon (
style: ButtonStyle (
backgroundColor:
MaterialStateProperty . all ( Colors . red ) ) ,
icon: const Icon ( Icons . stop ) ,
onPressed: serverModel . toggleService ,
label: Text ( translate ( " Stop service " ) ) )
. marginOnly ( bottom: 8 )
: SizedBox . shrink ( ) ,
2023-03-01 15:55:21 +08:00
PermissionRow ( translate ( " Screen Capture " ) , serverModel . mediaOk ,
serverModel . toggleService ) ,
PermissionRow ( translate ( " Input Control " ) , serverModel . inputOk ,
serverModel . toggleInput ) ,
PermissionRow ( translate ( " Transfer File " ) , serverModel . fileOk ,
serverModel . toggleFile ) ,
hasAudioPermission
? PermissionRow ( translate ( " Audio Capture " ) , serverModel . audioOk ,
serverModel . toggleAudio )
2023-03-07 17:43:55 +08:00
: Row ( children: [
Icon ( Icons . info_outline ) . marginOnly ( right: 15 ) ,
Expanded (
child: Text (
translate ( " android_version_audio_tip " ) ,
style: const TextStyle ( color: MyTheme . darkGray ) ,
) )
] )
2023-03-01 15:55:21 +08:00
] ) ) ;
2022-01-23 21:37:19 +08:00
}
2022-02-02 17:25:56 +08:00
}
2022-01-23 21:37:19 +08:00
class PermissionRow extends StatelessWidget {
2022-09-16 20:43:15 +08:00
const PermissionRow ( this . name , this . isOk , this . onPressed , { Key ? key } )
: super ( key: key ) ;
2022-01-23 21:37:19 +08:00
final String name ;
final bool isOk ;
final VoidCallback onPressed ;
@ override
Widget build ( BuildContext context ) {
2023-03-07 17:11:06 +08:00
return SwitchListTile (
visualDensity: VisualDensity . compact ,
contentPadding: EdgeInsets . all ( 0 ) ,
title: Text ( name ) ,
value: isOk ,
onChanged: ( bool value ) {
onPressed ( ) ;
} ) ;
2022-01-23 21:37:19 +08:00
}
}
2022-02-02 17:25:56 +08:00
class ConnectionManager extends StatelessWidget {
2022-09-16 20:43:15 +08:00
const ConnectionManager ( { Key ? key } ) : super ( key: key ) ;
2022-02-02 17:25:56 +08:00
@ override
Widget build ( BuildContext context ) {
final serverModel = Provider . of < ServerModel > ( context ) ;
2022-03-19 23:28:29 +08:00
return Column (
2022-08-22 20:18:31 +08:00
children: serverModel . clients
. map ( ( client ) = > PaddingCard (
title: translate ( client . isFileTransfer
2022-03-25 16:34:27 +08:00
? " File Connection "
: " Screen Connection " ) ,
2022-08-22 20:18:31 +08:00
titleIcon: client . isFileTransfer
2023-03-07 18:45:20 +08:00
? Icon ( Icons . folder_outlined )
: Icon ( Icons . mobile_screen_share ) ,
2023-03-10 01:31:34 +08:00
child: Column ( children: [
Row (
mainAxisAlignment: MainAxisAlignment . spaceBetween ,
2023-03-07 20:20:14 +08:00
children: [
2023-03-10 01:31:34 +08:00
Expanded ( child: ClientInfo ( client ) ) ,
Expanded (
flex: - 1 ,
child: client . isFileTransfer | | ! client . authorized
? const SizedBox . shrink ( )
: IconButton (
onPressed: ( ) {
2023-07-10 16:02:47 +08:00
gFFI . chatModel . changeCurrentKey (
2023-07-09 19:14:57 +08:00
MessageKey ( client . peerId , client . id ) ) ;
2023-03-10 01:31:34 +08:00
final bar = navigationBarKey . currentWidget ;
if ( bar ! = null ) {
bar as BottomNavigationBar ;
bar . onTap ! ( 1 ) ;
}
} ,
2023-07-10 21:03:35 +08:00
icon: unreadTopRightBuilder (
client . unreadChatMessageCount ) ) )
2023-03-10 01:31:34 +08:00
] ,
) ,
client . authorized
? const SizedBox . shrink ( )
: Text (
translate ( " android_new_connection_tip " ) ,
style: Theme . of ( context ) . textTheme . bodyMedium ,
) . marginOnly ( bottom: 5 ) ,
client . authorized
? Container (
alignment: Alignment . centerRight ,
child: ElevatedButton . icon (
style: ButtonStyle (
backgroundColor:
MaterialStatePropertyAll ( Colors . red ) ) ,
icon: const Icon ( Icons . close ) ,
onPressed: ( ) {
bind . cmCloseConnection ( connId: client . id ) ;
gFFI . invokeMethod (
" cancel_notification " , client . id ) ;
} ,
label: Text ( translate ( " Disconnect " ) ) ) )
: Row (
mainAxisAlignment: MainAxisAlignment . end ,
children: [
TextButton (
child: Text ( translate ( " Dismiss " ) ) ,
onPressed: ( ) {
serverModel . sendLoginResponse (
client , false ) ;
} ) . marginOnly ( right: 15 ) ,
2023-06-28 20:22:57 +08:00
if ( serverModel . approveMode ! = ' password ' )
ElevatedButton . icon (
icon: const Icon ( Icons . check ) ,
label: Text ( translate ( " Accept " ) ) ,
onPressed: ( ) {
serverModel . sendLoginResponse (
client , true ) ;
} ) ,
2023-03-10 01:31:34 +08:00
] ) ,
] ) ) )
2022-03-22 16:40:23 +08:00
. toList ( ) ) ;
2022-02-02 17:25:56 +08:00
}
}
2022-03-22 16:40:23 +08:00
class PaddingCard extends StatelessWidget {
2022-09-16 20:43:15 +08:00
const PaddingCard ( { Key ? key , required this . child , this . title , this . titleIcon } )
: super ( key: key ) ;
2022-01-23 21:37:19 +08:00
2022-03-22 16:40:23 +08:00
final String ? title ;
2023-03-07 18:45:20 +08:00
final Icon ? titleIcon ;
2022-03-22 16:40:23 +08:00
final Widget child ;
2022-02-02 17:25:56 +08:00
2022-03-22 16:40:23 +08:00
@ override
Widget build ( BuildContext context ) {
final children = [ child ] ;
if ( title ! = null ) {
children . insert (
0 ,
Padding (
2023-03-07 19:12:31 +08:00
padding: const EdgeInsets . fromLTRB ( 0 , 5 , 0 , 8 ) ,
2022-03-22 21:47:42 +08:00
child: Row (
children: [
2023-03-10 01:31:34 +08:00
titleIcon ? . marginOnly ( right: 10 ) ? ? const SizedBox . shrink ( ) ,
2023-03-07 18:45:20 +08:00
Expanded (
2023-03-09 19:09:45 +08:00
child: Text ( title ! ,
style: Theme . of ( context )
. textTheme
. titleLarge
? . merge ( TextStyle ( fontWeight: FontWeight . bold ) ) ) ,
2022-03-22 21:47:42 +08:00
)
] ,
2022-03-25 16:34:27 +08:00
) ) ) ;
2022-03-22 16:40:23 +08:00
}
2022-09-16 20:43:15 +08:00
return SizedBox (
2022-03-22 16:40:23 +08:00
width: double . maxFinite ,
child: Card (
2023-03-09 19:31:13 +08:00
shape: RoundedRectangleBorder (
borderRadius: BorderRadius . circular ( 13 ) ,
) ,
margin: const EdgeInsets . fromLTRB ( 12.0 , 10.0 , 12.0 , 0 ) ,
2022-03-22 16:40:23 +08:00
child: Padding (
2022-09-16 20:43:15 +08:00
padding:
2023-03-10 01:31:34 +08:00
const EdgeInsets . symmetric ( vertical: 15.0 , horizontal: 20.0 ) ,
2022-03-22 16:40:23 +08:00
child: Column (
children: children ,
) ,
) ,
) ) ;
}
2022-02-02 17:25:56 +08:00
}
2022-09-29 21:53:50 +08:00
class ClientInfo extends StatelessWidget {
final Client client ;
ClientInfo ( this . client ) ;
@ override
Widget build ( BuildContext context ) {
return Padding (
padding: const EdgeInsets . symmetric ( vertical: 8 ) ,
2023-03-10 01:31:34 +08:00
child: Column ( children: [
2022-09-29 21:53:50 +08:00
Row (
children: [
Expanded (
flex: - 1 ,
child: Padding (
padding: const EdgeInsets . only ( right: 12 ) ,
child: CircleAvatar (
2023-03-07 21:19:28 +08:00
backgroundColor: str2color (
client . name ,
Theme . of ( context ) . brightness = = Brightness . light
? 255
: 150 ) ,
2022-09-29 21:53:50 +08:00
child: Text ( client . name [ 0 ] ) ) ) ) ,
Expanded (
child: Column (
crossAxisAlignment: CrossAxisAlignment . start ,
children: [
2023-03-07 19:12:31 +08:00
Text ( client . name , style: const TextStyle ( fontSize: 18 ) ) ,
2022-09-29 21:53:50 +08:00
const SizedBox ( width: 8 ) ,
2023-03-07 19:12:31 +08:00
Text ( client . peerId , style: const TextStyle ( fontSize: 10 ) )
2022-09-29 21:53:50 +08:00
] ) )
] ,
) ,
] ) ) ;
}
2022-01-23 21:37:19 +08:00
}
2022-02-10 02:07:53 +08:00
2022-08-23 14:12:30 +08:00
void androidChannelInit ( ) {
2022-06-13 21:07:26 +08:00
gFFI . setMethodCallHandler ( ( method , arguments ) {
2022-02-25 21:54:05 +08:00
debugPrint ( " flutter got android msg, $ method , $ arguments " ) ;
2022-02-10 02:07:53 +08:00
try {
switch ( method ) {
case " start_capture " :
{
2022-08-12 18:42:02 +08:00
gFFI . dialogManager . dismissAll ( ) ;
2022-06-13 21:07:26 +08:00
gFFI . serverModel . updateClientState ( ) ;
2022-02-10 02:07:53 +08:00
break ;
}
2022-04-04 14:54:00 +08:00
case " on_state_changed " :
2022-02-10 02:07:53 +08:00
{
var name = arguments [ " name " ] as String ;
var value = arguments [ " value " ] as String = = " true " ;
2022-04-04 14:54:00 +08:00
debugPrint ( " from jvm:on_state_changed, $ name : $ value " ) ;
2022-06-13 21:07:26 +08:00
gFFI . serverModel . changeStatue ( name , value ) ;
2022-02-10 02:07:53 +08:00
break ;
}
2022-04-04 14:54:00 +08:00
case " on_android_permission_result " :
{
var type = arguments [ " type " ] as String ;
var result = arguments [ " result " ] as bool ;
2023-03-02 01:00:56 +08:00
AndroidPermissionManager . complete ( type , result ) ;
2022-04-04 14:54:00 +08:00
break ;
}
2022-04-12 20:54:29 +08:00
case " on_media_projection_canceled " :
{
2022-06-13 21:07:26 +08:00
gFFI . serverModel . stopService ( ) ;
2022-04-12 20:54:29 +08:00
break ;
}
2022-02-10 02:07:53 +08:00
}
} catch ( e ) {
2022-12-09 10:49:47 +08:00
debugPrintStack ( label: " MethodCallHandler err: $ e " ) ;
2022-02-10 02:07:53 +08:00
}
return " " ;
} ) ;
}