Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
R
rustdesk
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
李朝发
rustdesk
Commits
f1bbe9ca
Unverified
Commit
f1bbe9ca
authored
Sep 08, 2022
by
RustDesk
Committed by
GitHub
Sep 08, 2022
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1479 from Heap-Hop/master
Update flutter desktop
parents
29ad4c10
121111b8
Changes
15
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
273 additions
and
203 deletions
+273
-203
common.dart
flutter/lib/common.dart
+58
-1
file_manager_tab_page.dart
flutter/lib/desktop/pages/file_manager_tab_page.dart
+16
-2
port_forward_tab_page.dart
flutter/lib/desktop/pages/port_forward_tab_page.dart
+1
-2
remote_page.dart
flutter/lib/desktop/pages/remote_page.dart
+1
-3
remote_tab_page.dart
flutter/lib/desktop/pages/remote_tab_page.dart
+73
-63
desktop_remote_screen.dart
flutter/lib/desktop/screen/desktop_remote_screen.dart
+1
-1
remote_menubar.dart
flutter/lib/desktop/widgets/remote_menubar.dart
+11
-15
tabbar_widget.dart
flutter/lib/desktop/widgets/tabbar_widget.dart
+20
-6
remote_page.dart
flutter/lib/mobile/pages/remote_page.dart
+7
-12
overlay.dart
flutter/lib/mobile/widgets/overlay.dart
+40
-81
chat_model.dart
flutter/lib/models/chat_model.dart
+5
-2
model.dart
flutter/lib/models/model.dart
+4
-3
pubspec.lock
flutter/pubspec.lock
+9
-0
core_main.rs
src/core_main.rs
+10
-2
linux.rs
src/platform/linux.rs
+17
-10
No files found.
flutter/lib/common.dart
View file @
f1bbe9ca
...
...
@@ -14,6 +14,7 @@ import 'package:get/get.dart';
import
'package:shared_preferences/shared_preferences.dart'
;
import
'package:window_manager/window_manager.dart'
;
import
'mobile/widgets/overlay.dart'
;
import
'models/model.dart'
;
import
'models/platform_model.dart'
;
...
...
@@ -294,9 +295,11 @@ class Dialog<T> {
class
OverlayDialogManager
{
OverlayState
?
_overlayState
;
Map
<
String
,
Dialog
>
_dialogs
=
Map
()
;
final
Map
<
String
,
Dialog
>
_dialogs
=
{}
;
int
_tagCount
=
0
;
OverlayEntry
?
_mobileActionsOverlayEntry
;
/// By default OverlayDialogManager use global overlay
OverlayDialogManager
()
{
_overlayState
=
globalKey
.
currentState
?.
overlay
;
...
...
@@ -418,6 +421,60 @@ class OverlayDialogManager {
);
});
}
void
resetMobileActionsOverlay
({
FFI
?
ffi
})
{
if
(
_mobileActionsOverlayEntry
==
null
)
return
;
hideMobileActionsOverlay
();
showMobileActionsOverlay
(
ffi:
ffi
);
}
void
showMobileActionsOverlay
({
FFI
?
ffi
})
{
if
(
_mobileActionsOverlayEntry
!=
null
)
return
;
if
(
_overlayState
==
null
)
return
;
// compute overlay position
final
screenW
=
MediaQuery
.
of
(
globalKey
.
currentContext
!).
size
.
width
;
final
screenH
=
MediaQuery
.
of
(
globalKey
.
currentContext
!).
size
.
height
;
const
double
overlayW
=
200
;
const
double
overlayH
=
45
;
final
left
=
(
screenW
-
overlayW
)
/
2
;
final
top
=
screenH
-
overlayH
-
80
;
final
overlay
=
OverlayEntry
(
builder:
(
context
)
{
final
session
=
ffi
??
gFFI
;
return
DraggableMobileActions
(
position:
Offset
(
left
,
top
),
width:
overlayW
,
height:
overlayH
,
onBackPressed:
()
=>
session
.
tap
(
MouseButtons
.
right
),
onHomePressed:
()
=>
session
.
tap
(
MouseButtons
.
wheel
),
onRecentPressed:
()
async
{
session
.
sendMouse
(
'down'
,
MouseButtons
.
wheel
);
await
Future
.
delayed
(
const
Duration
(
milliseconds:
500
));
session
.
sendMouse
(
'up'
,
MouseButtons
.
wheel
);
},
onHidePressed:
()
=>
hideMobileActionsOverlay
(),
);
});
_overlayState
!.
insert
(
overlay
);
_mobileActionsOverlayEntry
=
overlay
;
}
void
hideMobileActionsOverlay
()
{
if
(
_mobileActionsOverlayEntry
!=
null
)
{
_mobileActionsOverlayEntry
!.
remove
();
_mobileActionsOverlayEntry
=
null
;
return
;
}
}
void
toggleMobileActionsOverlay
({
FFI
?
ffi
})
{
if
(
_mobileActionsOverlayEntry
==
null
)
{
showMobileActionsOverlay
(
ffi:
ffi
);
}
else
{
hideMobileActionsOverlay
();
}
}
}
void
showToast
(
String
text
,
{
Duration
timeout
=
const
Duration
(
seconds:
2
)})
{
...
...
flutter/lib/desktop/pages/file_manager_tab_page.dart
View file @
f1bbe9ca
...
...
@@ -8,6 +8,8 @@ import 'package:flutter_hbb/desktop/widgets/tabbar_widget.dart';
import
'package:flutter_hbb/utils/multi_window_manager.dart'
;
import
'package:get/get.dart'
;
import
'../../mobile/widgets/dialog.dart'
;
/// File Transfer for multi tabs
class
FileManagerTabPage
extends
StatefulWidget
{
final
Map
<
String
,
dynamic
>
params
;
...
...
@@ -31,6 +33,7 @@ class _FileManagerTabPageState extends State<FileManagerTabPage> {
label:
params
[
'id'
],
selectedIcon:
selectedIcon
,
unselectedIcon:
unselectedIcon
,
onTabCloseButton:
()
=>
handleTabCloseButton
(
params
[
'id'
]),
page:
FileManagerPage
(
key:
ValueKey
(
params
[
'id'
]),
id:
params
[
'id'
])));
}
...
...
@@ -53,6 +56,7 @@ class _FileManagerTabPageState extends State<FileManagerTabPage> {
label:
id
,
selectedIcon:
selectedIcon
,
unselectedIcon:
unselectedIcon
,
onTabCloseButton:
()
=>
handleTabCloseButton
(
id
),
page:
FileManagerPage
(
key:
ValueKey
(
id
),
id:
id
)));
}
else
if
(
call
.
method
==
"onDestroy"
)
{
tabController
.
clear
();
...
...
@@ -71,10 +75,10 @@ class _FileManagerTabPageState extends State<FileManagerTabPage> {
backgroundColor:
MyTheme
.
color
(
context
).
bg
,
body:
DesktopTab
(
controller:
tabController
,
on
Close
:
()
{
on
WindowCloseButton
:
()
{
tabController
.
clear
();
},
tail:
AddButton
().
paddingOnly
(
left:
10
),
tail:
const
AddButton
().
paddingOnly
(
left:
10
),
)),
),
);
...
...
@@ -89,4 +93,14 @@ class _FileManagerTabPageState extends State<FileManagerTabPage> {
int
windowId
()
{
return
widget
.
params
[
"windowId"
];
}
void
handleTabCloseButton
(
String
peerId
)
{
final
session
=
ffi
(
'ft_
$peerId
'
);
if
(
session
.
ffiModel
.
pi
.
hostname
.
isNotEmpty
)
{
tabController
.
jumpBy
(
peerId
);
clientClose
(
session
.
dialogManager
);
}
else
{
tabController
.
closeBy
(
peerId
);
}
}
}
flutter/lib/desktop/pages/port_forward_tab_page.dart
View file @
f1bbe9ca
...
...
@@ -78,7 +78,7 @@ class _PortForwardTabPageState extends State<PortForwardTabPage> {
backgroundColor:
MyTheme
.
color
(
context
).
bg
,
body:
DesktopTab
(
controller:
tabController
,
on
Close
:
()
{
on
WindowCloseButton
:
()
{
tabController
.
clear
();
},
tail:
AddButton
().
paddingOnly
(
left:
10
),
...
...
@@ -88,7 +88,6 @@ class _PortForwardTabPageState extends State<PortForwardTabPage> {
}
void
onRemoveId
(
String
id
)
{
ffi
(
"pf_
$id
"
).
close
();
if
(
tabController
.
state
.
value
.
tabs
.
isEmpty
)
{
WindowController
.
fromWindowId
(
windowId
()).
hide
();
}
...
...
flutter/lib/desktop/pages/remote_page.dart
View file @
f1bbe9ca
import
'dart:async'
;
import
'dart:io'
;
import
'dart:typed_data'
;
import
'dart:ui'
as
ui
;
import
'package:flutter/gestures.dart'
;
...
...
@@ -16,7 +15,6 @@ import 'package:flutter_custom_cursor/flutter_custom_cursor.dart';
import
'../widgets/remote_menubar.dart'
;
import
'../../common.dart'
;
import
'../../mobile/widgets/dialog.dart'
;
import
'../../mobile/widgets/overlay.dart'
;
import
'../../models/model.dart'
;
import
'../../models/platform_model.dart'
;
import
'../../common/shared_state.dart'
;
...
...
@@ -107,7 +105,7 @@ class _RemotePageState extends State<RemotePage>
@override
void
dispose
()
{
debugPrint
(
"REMOTE PAGE dispose
${widget.id}
"
);
hideMobileActionsOverlay
();
_ffi
.
dialogManager
.
hideMobileActionsOverlay
();
_ffi
.
listenToMouse
(
false
);
_mobileFocusNode
.
dispose
();
_physicalFocusNode
.
dispose
();
...
...
flutter/lib/desktop/pages/
connection
_tab_page.dart
→
flutter/lib/desktop/pages/
remote
_tab_page.dart
View file @
f1bbe9ca
...
...
@@ -10,6 +10,8 @@ import 'package:flutter_hbb/desktop/widgets/tabbar_widget.dart';
import
'package:flutter_hbb/utils/multi_window_manager.dart'
;
import
'package:get/get.dart'
;
import
'../../mobile/widgets/dialog.dart'
;
class
ConnectionTabPage
extends
StatefulWidget
{
final
Map
<
String
,
dynamic
>
params
;
...
...
@@ -37,12 +39,12 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
label:
peerId
,
selectedIcon:
selectedIcon
,
unselectedIcon:
unselectedIcon
,
page:
Obx
(()
=>
RemotePage
(
key:
ValueKey
(
peerId
),
id:
peerId
,
tabBarHeight:
fullscreen
.
isTrue
?
0
:
kDesktopRemoteTabBarHeight
,
)
)));
onTabCloseButton:
()
=>
handleTabCloseButton
(
peerId
),
page:
RemotePage
(
key:
ValueKey
(
peerId
)
,
id:
peerId
,
tabBarHeight:
fullscreen
.
isTrue
?
0
:
kDesktopRemoteTabBarHeight
,
)));
}
}
...
...
@@ -69,12 +71,12 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
label:
id
,
selectedIcon:
selectedIcon
,
unselectedIcon:
unselectedIcon
,
page:
Obx
(()
=>
RemotePage
(
key:
ValueKey
(
id
),
id:
id
,
tabBarHeight:
fullscreen
.
isTrue
?
0
:
kDesktopRemoteTabBarHeight
,
)
)));
onTabCloseButton:
()
=>
handleTabCloseButton
(
id
),
page:
RemotePage
(
key:
ValueKey
(
id
)
,
id:
id
,
tabBarHeight:
fullscreen
.
isTrue
?
0
:
kDesktopRemoteTabBarHeight
,
)));
}
else
if
(
call
.
method
==
"onDestroy"
)
{
tabController
.
clear
();
}
...
...
@@ -92,57 +94,55 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
border:
Border
.
all
(
color:
MyTheme
.
color
(
context
).
border
!)),
child:
Scaffold
(
backgroundColor:
MyTheme
.
color
(
context
).
bg
,
body:
Obx
(()
=>
DesktopTab
(
controller:
tabController
,
showTabBar:
fullscreen
.
isFalse
,
onClose:
()
{
tabController
.
clear
();
},
tail:
AddButton
().
paddingOnly
(
left:
10
),
pageViewBuilder:
(
pageView
)
{
WindowController
.
fromWindowId
(
windowId
())
.
setFullscreen
(
fullscreen
.
isTrue
);
return
pageView
;
},
tabBuilder:
(
key
,
icon
,
label
,
themeConf
)
=>
Obx
(()
{
final
connectionType
=
ConnectionTypeState
.
find
(
key
);
if
(!
connectionType
.
isValid
())
{
return
Row
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
[
icon
,
label
,
],
);
}
else
{
final
msgDirect
=
translate
(
connectionType
.
direct
.
value
==
ConnectionType
.
strDirect
?
'Direct Connection'
:
'Relay Connection'
);
final
msgSecure
=
translate
(
connectionType
.
secure
.
value
==
ConnectionType
.
strSecure
?
'Secure Connection'
:
'Insecure Connection'
);
return
Row
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
[
icon
,
Tooltip
(
message:
'
$msgDirect
\n
$msgSecure
'
,
child:
Image
.
asset
(
'assets/
${connectionType.secure.value}${connectionType.direct.value}
.png'
,
width:
themeConf
.
iconSize
,
height:
themeConf
.
iconSize
,
).
paddingOnly
(
right:
5
),
),
label
,
],
);
}
}),
))),
body:
DesktopTab
(
controller:
tabController
,
showTabBar:
fullscreen
.
isFalse
,
onWindowCloseButton:
()
{
tabController
.
clear
();
},
tail:
AddButton
().
paddingOnly
(
left:
10
),
pageViewBuilder:
(
pageView
)
{
WindowController
.
fromWindowId
(
windowId
())
.
setFullscreen
(
fullscreen
.
isTrue
);
return
pageView
;
},
tabBuilder:
(
key
,
icon
,
label
,
themeConf
)
=>
Obx
(()
{
final
connectionType
=
ConnectionTypeState
.
find
(
key
);
if
(!
connectionType
.
isValid
())
{
return
Row
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
[
icon
,
label
,
],
);
}
else
{
final
msgDirect
=
translate
(
connectionType
.
direct
.
value
==
ConnectionType
.
strDirect
?
'Direct Connection'
:
'Relay Connection'
);
final
msgSecure
=
translate
(
connectionType
.
secure
.
value
==
ConnectionType
.
strSecure
?
'Secure Connection'
:
'Insecure Connection'
);
return
Row
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
[
icon
,
Tooltip
(
message:
'
$msgDirect
\n
$msgSecure
'
,
child:
Image
.
asset
(
'assets/
${connectionType.secure.value}${connectionType.direct.value}
.png'
,
width:
themeConf
.
iconSize
,
height:
themeConf
.
iconSize
,
).
paddingOnly
(
right:
5
),
),
label
,
],
);
}
}),
)),
),
));
}
...
...
@@ -157,4 +157,14 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
int
windowId
()
{
return
widget
.
params
[
"windowId"
];
}
void
handleTabCloseButton
(
String
peerId
)
{
final
session
=
ffi
(
peerId
);
if
(
session
.
ffiModel
.
pi
.
hostname
.
isNotEmpty
)
{
tabController
.
jumpBy
(
peerId
);
clientClose
(
session
.
dialogManager
);
}
else
{
tabController
.
closeBy
(
peerId
);
}
}
}
flutter/lib/desktop/screen/desktop_remote_screen.dart
View file @
f1bbe9ca
import
'package:flutter/material.dart'
;
import
'package:flutter_hbb/common.dart'
;
import
'package:flutter_hbb/desktop/pages/
connection
_tab_page.dart'
;
import
'package:flutter_hbb/desktop/pages/
remote
_tab_page.dart'
;
import
'package:get/get.dart'
;
import
'package:provider/provider.dart'
;
...
...
flutter/lib/desktop/widgets/remote_menubar.dart
View file @
f1bbe9ca
...
...
@@ -6,7 +6,6 @@ import 'package:rxdart/rxdart.dart' as rxdart;
import
'../../common.dart'
;
import
'../../mobile/widgets/dialog.dart'
;
import
'../../mobile/widgets/overlay.dart'
;
import
'../../models/model.dart'
;
import
'../../models/platform_model.dart'
;
import
'../../common/shared_state.dart'
;
...
...
@@ -75,20 +74,17 @@ class _RemoteMenubarState extends State<RemoteMenubar> {
final
List
<
Widget
>
menubarItems
=
[];
if
(!
isWebDesktop
)
{
menubarItems
.
add
(
_buildFullscreen
(
context
));
//if (widget.ffi.ffiModel.isPeerAndroid) {
menubarItems
.
add
(
IconButton
(
tooltip:
translate
(
'Mobile Actions'
),
color:
_MenubarTheme
.
commonColor
,
icon:
const
Icon
(
Icons
.
build
),
onPressed:
()
{
if
(
mobileActionsOverlayEntry
==
null
)
{
showMobileActionsOverlay
();
}
else
{
hideMobileActionsOverlay
();
}
},
));
//}
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
);
},
));
}
}
menubarItems
.
add
(
_buildMonitor
(
context
));
menubarItems
.
add
(
_buildControl
(
context
));
...
...
flutter/lib/desktop/widgets/tabbar_widget.dart
View file @
f1bbe9ca
...
...
@@ -25,6 +25,7 @@ class TabInfo {
final
IconData
?
selectedIcon
;
final
IconData
?
unselectedIcon
;
final
bool
closable
;
final
VoidCallback
?
onTabCloseButton
;
final
Widget
page
;
TabInfo
(
...
...
@@ -33,6 +34,7 @@ class TabInfo {
this
.
selectedIcon
,
this
.
unselectedIcon
,
this
.
closable
=
true
,
this
.
onTabCloseButton
,
required
this
.
page
});
}
...
...
@@ -137,6 +139,12 @@ class DesktopTabController {
}
}
void
jumpBy
(
String
key
)
{
if
(!
isDesktop
)
return
;
final
index
=
state
.
value
.
tabs
.
indexWhere
((
tab
)
=>
tab
.
key
==
key
);
jumpTo
(
index
);
}
void
closeBy
(
String
?
key
)
{
if
(!
isDesktop
)
return
;
assert
(
onRemove
!=
null
);
...
...
@@ -145,8 +153,8 @@ class DesktopTabController {
remove
(
state
.
value
.
selected
);
}
}
else
{
state
.
value
.
tabs
.
indexWhere
((
tab
)
=>
tab
.
key
==
key
);
remove
(
state
.
value
.
selected
);
final
index
=
state
.
value
.
tabs
.
indexWhere
((
tab
)
=>
tab
.
key
==
key
);
remove
(
index
);
}
}
...
...
@@ -175,7 +183,7 @@ class DesktopTab extends StatelessWidget {
final
bool
showClose
;
final
Widget
Function
(
Widget
pageView
)?
pageViewBuilder
;
final
Widget
?
tail
;
final
VoidCallback
?
on
Close
;
final
VoidCallback
?
on
WindowCloseButton
;
final
TabBuilder
?
tabBuilder
;
final
LabelGetter
?
labelGetter
;
...
...
@@ -196,7 +204,7 @@ class DesktopTab extends StatelessWidget {
this
.
showClose
=
true
,
this
.
pageViewBuilder
,
this
.
tail
,
this
.
on
Close
,
this
.
on
WindowCloseButton
,
this
.
tabBuilder
,
this
.
labelGetter
,
})
:
super
(
key:
key
)
{
...
...
@@ -333,7 +341,7 @@ class DesktopTab extends StatelessWidget {
showMinimize:
showMinimize
,
showMaximize:
showMaximize
,
showClose:
showClose
,
onClose:
on
Close
,
onClose:
on
WindowCloseButton
,
)
],
);
...
...
@@ -511,7 +519,13 @@ class _ListView extends StatelessWidget {
unselectedIcon:
tab
.
unselectedIcon
,
closable:
tab
.
closable
,
selected:
state
.
value
.
selected
,
onClose:
()
=>
controller
.
remove
(
index
),
onClose:
()
{
if
(
tab
.
onTabCloseButton
!=
null
)
{
tab
.
onTabCloseButton
!();
}
else
{
controller
.
remove
(
index
);
}
},
onSelected:
()
=>
controller
.
jumpTo
(
index
),
tabBuilder:
tabBuilder
==
null
?
null
...
...
flutter/lib/mobile/pages/remote_page.dart
View file @
f1bbe9ca
...
...
@@ -14,7 +14,6 @@ import '../../models/model.dart';
import
'../../models/platform_model.dart'
;
import
'../widgets/dialog.dart'
;
import
'../widgets/gestures.dart'
;
import
'../widgets/overlay.dart'
;
final
initText
=
'
\
1'
*
1024
;
...
...
@@ -64,7 +63,7 @@ class _RemotePageState extends State<RemotePage> {
@override
void
dispose
()
{
hideMobileActionsOverlay
();
gFFI
.
dialogManager
.
hideMobileActionsOverlay
();
gFFI
.
listenToMouse
(
false
);
gFFI
.
invokeMethod
(
"enable_soft_keyboard"
,
true
);
_mobileFocusNode
.
dispose
();
...
...
@@ -266,8 +265,9 @@ class _RemotePageState extends State<RemotePage> {
:
SafeArea
(
child:
OrientationBuilder
(
builder:
(
ctx
,
orientation
)
{
if
(
_currentOrientation
!=
orientation
)
{
Timer
(
Duration
(
milliseconds:
200
),
()
{
resetMobileActionsOverlay
();
Timer
(
const
Duration
(
milliseconds:
200
),
()
{
gFFI
.
dialogManager
.
resetMobileActionsOverlay
(
ffi:
gFFI
);
_currentOrientation
=
orientation
;
gFFI
.
canvasModel
.
updateViewStyle
();
});
...
...
@@ -422,14 +422,9 @@ class _RemotePageState extends State<RemotePage> {
?
[
IconButton
(
color:
Colors
.
white
,
icon:
Icon
(
Icons
.
build
),
onPressed:
()
{
if
(
mobileActionsOverlayEntry
==
null
)
{
showMobileActionsOverlay
();
}
else
{
hideMobileActionsOverlay
();
}
},
icon:
const
Icon
(
Icons
.
build
),
onPressed:
()
=>
gFFI
.
dialogManager
.
toggleMobileActionsOverlay
(
ffi:
gFFI
),
)
]
:
[
...
...
flutter/lib/mobile/widgets/overlay.dart
View file @
f1bbe9ca
...
...
@@ -2,11 +2,8 @@ import 'package:flutter/material.dart';
import
'package:flutter_hbb/common.dart'
;
import
'../../models/chat_model.dart'
;
import
'../../models/model.dart'
;
import
'../pages/chat_page.dart'
;
OverlayEntry
?
mobileActionsOverlayEntry
;
class
DraggableChatWindow
extends
StatelessWidget
{
DraggableChatWindow
(
{
this
.
position
=
Offset
.
zero
,
...
...
@@ -99,6 +96,7 @@ class DraggableMobileActions extends StatelessWidget {
this
.
onBackPressed
,
this
.
onRecentPressed
,
this
.
onHomePressed
,
this
.
onHidePressed
,
required
this
.
width
,
required
this
.
height
});
...
...
@@ -108,6 +106,7 @@ class DraggableMobileActions extends StatelessWidget {
final
VoidCallback
?
onBackPressed
;
final
VoidCallback
?
onHomePressed
;
final
VoidCallback
?
onRecentPressed
;
final
VoidCallback
?
onHidePressed
;
@override
Widget
build
(
BuildContext
context
)
{
...
...
@@ -118,89 +117,49 @@ class DraggableMobileActions extends StatelessWidget {
builder:
(
_
,
onPanUpdate
)
{
return
GestureDetector
(
onPanUpdate:
onPanUpdate
,
child:
Container
(
decoration:
BoxDecoration
(
color:
MyTheme
.
accent
.
withOpacity
(
0.4
),
borderRadius:
BorderRadius
.
all
(
Radius
.
circular
(
15
))),
child:
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceAround
,
children:
[
IconButton
(
color:
MyTheme
.
white
,
onPressed:
onBackPressed
,
icon:
Icon
(
Icons
.
arrow_back
)),
IconButton
(
color:
MyTheme
.
white
,
onPressed:
onHomePressed
,
icon:
Icon
(
Icons
.
home
)),
IconButton
(
color:
MyTheme
.
white
,
onPressed:
onRecentPressed
,
icon:
Icon
(
Icons
.
more_horiz
)),
VerticalDivider
(
width:
0
,
thickness:
2
,
indent:
10
,
endIndent:
10
,
child:
Card
(
color:
Colors
.
transparent
,
shadowColor:
Colors
.
transparent
,
child:
Container
(
decoration:
BoxDecoration
(
color:
MyTheme
.
accent
.
withOpacity
(
0.4
),
borderRadius:
BorderRadius
.
all
(
Radius
.
circular
(
15
))),
child:
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceAround
,
children:
[
IconButton
(
color:
MyTheme
.
white
,
onPressed:
onBackPressed
,
splashRadius:
20
,
icon:
const
Icon
(
Icons
.
arrow_back
)),
IconButton
(
color:
MyTheme
.
white
,
onPressed:
onHomePressed
,
splashRadius:
20
,
icon:
const
Icon
(
Icons
.
home
)),
IconButton
(
color:
MyTheme
.
white
,
onPressed:
onRecentPressed
,
splashRadius:
20
,
icon:
const
Icon
(
Icons
.
more_horiz
)),
const
VerticalDivider
(
width:
0
,
thickness:
2
,
indent:
10
,
endIndent:
10
,
),
IconButton
(
color:
MyTheme
.
white
,
onPressed:
onHidePressed
,
splashRadius:
20
,
icon:
const
Icon
(
Icons
.
keyboard_arrow_down
)),
],
),
IconButton
(
color:
MyTheme
.
white
,
onPressed:
hideMobileActionsOverlay
,
icon:
Icon
(
Icons
.
keyboard_arrow_down
)),
],
),
));
)));
});
}
}
resetMobileActionsOverlay
()
{
if
(
mobileActionsOverlayEntry
==
null
)
return
;
hideMobileActionsOverlay
();
showMobileActionsOverlay
();
}
showMobileActionsOverlay
()
{
if
(
mobileActionsOverlayEntry
!=
null
)
return
;
if
(
globalKey
.
currentContext
==
null
||
globalKey
.
currentState
==
null
||
globalKey
.
currentState
!.
overlay
==
null
)
return
;
final
globalOverlayState
=
globalKey
.
currentState
!.
overlay
!;
// compute overlay position
final
screenW
=
MediaQuery
.
of
(
globalKey
.
currentContext
!).
size
.
width
;
final
screenH
=
MediaQuery
.
of
(
globalKey
.
currentContext
!).
size
.
height
;
final
double
overlayW
=
200
;
final
double
overlayH
=
45
;
final
left
=
(
screenW
-
overlayW
)
/
2
;
final
top
=
screenH
-
overlayH
-
80
;
final
overlay
=
OverlayEntry
(
builder:
(
context
)
{
return
DraggableMobileActions
(
position:
Offset
(
left
,
top
),
width:
overlayW
,
height:
overlayH
,
onBackPressed:
()
=>
gFFI
.
tap
(
MouseButtons
.
right
),
onHomePressed:
()
=>
gFFI
.
tap
(
MouseButtons
.
wheel
),
onRecentPressed:
()
async
{
gFFI
.
sendMouse
(
'down'
,
MouseButtons
.
wheel
);
await
Future
.
delayed
(
Duration
(
milliseconds:
500
));
gFFI
.
sendMouse
(
'up'
,
MouseButtons
.
wheel
);
},
);
});
globalOverlayState
.
insert
(
overlay
);
mobileActionsOverlayEntry
=
overlay
;
}
hideMobileActionsOverlay
()
{
if
(
mobileActionsOverlayEntry
!=
null
)
{
mobileActionsOverlayEntry
!.
remove
();
mobileActionsOverlayEntry
=
null
;
return
;
}
}
class
Draggable
extends
StatefulWidget
{
Draggable
(
{
this
.
checkKeyboard
=
false
,
...
...
flutter/lib/models/chat_model.dart
View file @
f1bbe9ca
...
...
@@ -143,9 +143,12 @@ class ChatModel with ChangeNotifier {
}
toggleChatOverlay
()
{
if
(
chatIconOverlayEntry
==
null
||
chatWindowOverlayEntry
==
null
)
{
if
((!
isDesktop
&&
chatIconOverlayEntry
==
null
)
||
chatWindowOverlayEntry
==
null
)
{
gFFI
.
invokeMethod
(
"enable_soft_keyboard"
,
true
);
showChatIconOverlay
();
if
(!
isDesktop
)
{
showChatIconOverlay
();
}
showChatWindowOverlay
();
}
else
{
hideChatIconOverlay
();
...
...
flutter/lib/models/model.dart
View file @
f1bbe9ca
...
...
@@ -22,7 +22,6 @@ import 'package:flutter_custom_cursor/flutter_custom_cursor.dart';
import
'../common.dart'
;
import
'../common/shared_state.dart'
;
import
'../mobile/widgets/dialog.dart'
;
import
'../mobile/widgets/overlay.dart'
;
import
'peer_model.dart'
;
import
'platform_model.dart'
;
...
...
@@ -267,8 +266,10 @@ class FfiModel with ChangeNotifier {
if
(
isPeerAndroid
)
{
_touchMode
=
true
;
if
(
parent
.
target
?.
ffiModel
.
permissions
[
'keyboard'
]
!=
false
)
{
Timer
(
const
Duration
(
milliseconds:
100
),
showMobileActionsOverlay
);
if
(
parent
.
target
!=
null
&&
parent
.
target
!.
ffiModel
.
permissions
[
'keyboard'
]
!=
false
)
{
Timer
(
const
Duration
(
milliseconds:
100
),
parent
.
target
!.
dialogManager
.
showMobileActionsOverlay
);
}
}
else
{
_touchMode
=
...
...
flutter/pubspec.lock
View file @
f1bbe9ca
...
...
@@ -414,6 +414,15 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.3.0"
flutter_custom_cursor:
dependency: "direct main"
description:
path: "."
ref: "9021e21de36c84edf01d5034f38eda580463163b"
resolved-ref: "9021e21de36c84edf01d5034f38eda580463163b"
url: "https://github.com/Kingtous/rustdesk_flutter_custom_cursor"
source: git
version: "0.0.1"
flutter_launcher_icons:
dependency: "direct dev"
description:
...
...
src/core_main.rs
View file @
f1bbe9ca
use
hbb_common
::
log
;
use
crate
::{
start_os_service
,
flutter
::
connection_manager
};
use
crate
::{
start_os_service
,
flutter
::
connection_manager
,
start_server
};
/// Main entry of the RustDesk Core.
/// Return true if the app should continue running with UI(possibly Flutter), false if the app should exit.
...
...
@@ -20,7 +20,15 @@ pub fn core_main() -> bool {
return
false
;
}
if
args
[
1
]
==
"--server"
{
// TODO: server
log
::
info!
(
"start --server"
);
#[cfg(not(target_os
=
"macos"
))]
{
start_server
(
true
);
}
#[cfg(target_os
=
"macos"
)]
{
std
::
thread
::
spawn
(
move
||
start_server
(
true
));
}
return
false
;
}
}
...
...
src/platform/linux.rs
View file @
f1bbe9ca
...
...
@@ -525,20 +525,27 @@ pub fn is_root() -> bool {
crate
::
username
()
==
"root"
}
fn
is_opensuse
()
->
bool
{
if
let
Ok
(
res
)
=
run_cmds
(
"cat /etc/os-release | grep opensuse"
.to_owned
())
{
if
!
res
.is_empty
()
{
return
true
;
}
}
false
}
pub
fn
run_as_user
(
arg
:
&
str
)
->
ResultType
<
Option
<
std
::
process
::
Child
>>
{
let
uid
=
get_active_userid
();
let
cmd
=
std
::
env
::
current_exe
()
?
;
let
xdg
=
&
format!
(
"XDG_RUNTIME_DIR=/run/user/{}"
,
uid
)
as
&
str
;
let
username
=
&
get_active_username
();
let
mut
args
=
vec!
[
xdg
,
"-u"
,
username
,
cmd
.to_str
()
.unwrap_or
(
""
),
arg
];
// -E required for opensuse
let
task
=
std
::
process
::
Command
::
new
(
"sudo"
)
.args
(
vec!
[
"-E"
,
&
format!
(
"XDG_RUNTIME_DIR=/run/user/{}"
,
uid
)
as
&
str
,
"-u"
,
&
get_active_username
(),
cmd
.to_str
()
.unwrap_or
(
""
),
arg
,
])
.spawn
()
?
;
if
is_opensuse
()
{
args
.insert
(
0
,
"-E"
);
}
let
task
=
std
::
process
::
Command
::
new
(
"sudo"
)
.args
(
args
)
.spawn
()
?
;
Ok
(
Some
(
task
))
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment