mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-11-05 08:37:15 +00:00
Add Without password actions and pass the selection through desktop, mobile and Web sessions. Omit the password when constructing LoginRequest, preserve saved credentials, and reuse the existing approval and OS login dialogs. Keep protocol and controlled-side authentication changes separate.
261 lines
7.1 KiB
Dart
261 lines
7.1 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_hbb/mobile/pages/server_page.dart';
|
|
import 'package:flutter_hbb/mobile/pages/settings_page.dart';
|
|
import 'package:flutter_hbb/web/settings_page.dart';
|
|
import 'package:get/get.dart';
|
|
import '../../common.dart';
|
|
import '../../common/widgets/chat_page.dart';
|
|
import '../../models/platform_model.dart';
|
|
import '../../models/state_model.dart';
|
|
import 'connection_page.dart';
|
|
|
|
abstract class PageShape extends Widget {
|
|
final String title = "";
|
|
final Widget icon = Icon(null);
|
|
final List<Widget> appBarActions = [];
|
|
}
|
|
|
|
class HomePage extends StatefulWidget {
|
|
static final homeKey = GlobalKey<HomePageState>();
|
|
|
|
HomePage() : super(key: homeKey);
|
|
|
|
@override
|
|
HomePageState createState() => HomePageState();
|
|
}
|
|
|
|
class HomePageState extends State<HomePage> {
|
|
var _selectedIndex = 0;
|
|
int get selectedIndex => _selectedIndex;
|
|
final List<PageShape> _pages = [];
|
|
int _chatPageTabIndex = -1;
|
|
bool get isChatPageCurrentTab => isAndroid
|
|
? _selectedIndex == _chatPageTabIndex
|
|
: false; // change this when ios have chat page
|
|
|
|
void refreshPages() {
|
|
setState(() {
|
|
initPages();
|
|
});
|
|
}
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
initPages();
|
|
}
|
|
|
|
void initPages() {
|
|
_pages.clear();
|
|
if (!bind.isIncomingOnly()) {
|
|
_pages.add(ConnectionPage(
|
|
appBarActions: [],
|
|
));
|
|
}
|
|
if (isAndroid && !bind.isOutgoingOnly()) {
|
|
_chatPageTabIndex = _pages.length;
|
|
_pages.addAll([ChatPage(type: ChatPageType.mobileMain), ServerPage()]);
|
|
}
|
|
_pages.add(SettingsPage());
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return WillPopScope(
|
|
onWillPop: () async {
|
|
if (_selectedIndex != 0) {
|
|
setState(() {
|
|
_selectedIndex = 0;
|
|
});
|
|
} else {
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
child: Scaffold(
|
|
// backgroundColor: MyTheme.grayBg,
|
|
appBar: AppBar(
|
|
centerTitle: true,
|
|
title: appTitle(),
|
|
actions: _pages.elementAt(_selectedIndex).appBarActions,
|
|
),
|
|
bottomNavigationBar: BottomNavigationBar(
|
|
key: navigationBarKey,
|
|
items: _pages
|
|
.map((page) =>
|
|
BottomNavigationBarItem(icon: page.icon, label: page.title))
|
|
.toList(),
|
|
currentIndex: _selectedIndex,
|
|
type: BottomNavigationBarType.fixed,
|
|
selectedItemColor: MyTheme.accent, //
|
|
unselectedItemColor: MyTheme.darkGray,
|
|
onTap: (index) => setState(() {
|
|
// close chat overlay when go chat page
|
|
if (_selectedIndex != index) {
|
|
_selectedIndex = index;
|
|
if (isChatPageCurrentTab) {
|
|
gFFI.chatModel.hideChatIconOverlay();
|
|
gFFI.chatModel.hideChatWindowOverlay();
|
|
gFFI.chatModel.mobileClearClientUnread(
|
|
gFFI.chatModel.currentKey.connId);
|
|
}
|
|
}
|
|
}),
|
|
),
|
|
body: _pages.elementAt(_selectedIndex),
|
|
));
|
|
}
|
|
|
|
Widget appTitle() {
|
|
final currentUser = gFFI.chatModel.currentUser;
|
|
final currentKey = gFFI.chatModel.currentKey;
|
|
if (isChatPageCurrentTab &&
|
|
currentUser != null &&
|
|
currentKey.peerId.isNotEmpty) {
|
|
final connected =
|
|
gFFI.serverModel.clients.any((e) => e.id == currentKey.connId);
|
|
return Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
Tooltip(
|
|
message: currentKey.isOut
|
|
? translate('Outgoing connection')
|
|
: translate('Incoming connection'),
|
|
child: Icon(
|
|
currentKey.isOut
|
|
? Icons.call_made_rounded
|
|
: Icons.call_received_rounded,
|
|
),
|
|
),
|
|
Expanded(
|
|
child: Center(
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
Text(
|
|
"${currentUser.firstName} ${currentUser.id}",
|
|
),
|
|
if (connected)
|
|
Container(
|
|
width: 10,
|
|
height: 10,
|
|
decoration: BoxDecoration(
|
|
shape: BoxShape.circle,
|
|
color: Color.fromARGB(255, 133, 246, 199)),
|
|
).marginSymmetric(horizontal: 2),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
return Text(bind.mainGetAppNameSync());
|
|
}
|
|
}
|
|
|
|
class WebHomePage extends StatelessWidget {
|
|
final connectionPage =
|
|
ConnectionPage(appBarActions: <Widget>[const WebSettingsPage()]);
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
stateGlobal.isInMainPage = true;
|
|
handleUnilink(context);
|
|
return Scaffold(
|
|
// backgroundColor: MyTheme.grayBg,
|
|
appBar: AppBar(
|
|
centerTitle: true,
|
|
title: Text("${bind.mainGetAppNameSync()} (Preview)"),
|
|
actions: connectionPage.appBarActions,
|
|
),
|
|
body: connectionPage,
|
|
);
|
|
}
|
|
|
|
handleUnilink(BuildContext context) {
|
|
if (webInitialLink.isEmpty) {
|
|
return;
|
|
}
|
|
final link = webInitialLink;
|
|
webInitialLink = '';
|
|
final splitter = ["/#/", "/#", "#/", "#"];
|
|
var fakelink = '';
|
|
for (var s in splitter) {
|
|
if (link.contains(s)) {
|
|
var list = link.split(s);
|
|
if (list.length < 2 || list[1].isEmpty) {
|
|
return;
|
|
}
|
|
list.removeAt(0);
|
|
fakelink = "rustdesk://${list.join(s)}";
|
|
break;
|
|
}
|
|
}
|
|
if (fakelink.isEmpty) {
|
|
return;
|
|
}
|
|
final uri = Uri.tryParse(fakelink);
|
|
if (uri == null) {
|
|
return;
|
|
}
|
|
final args = urlLinkToCmdArgs(uri);
|
|
if (args == null || args.isEmpty) {
|
|
return;
|
|
}
|
|
bool isFileTransfer = false;
|
|
bool isViewCamera = false;
|
|
bool isTerminal = false;
|
|
String? id;
|
|
String? password;
|
|
var loginMethod = '';
|
|
for (int i = 0; i < args.length; i++) {
|
|
switch (args[i]) {
|
|
case '--connect':
|
|
case '--play':
|
|
id = args[i + 1];
|
|
i++;
|
|
break;
|
|
case '--file-transfer':
|
|
isFileTransfer = true;
|
|
id = args[i + 1];
|
|
i++;
|
|
break;
|
|
case '--view-camera':
|
|
isViewCamera = true;
|
|
id = args[i + 1];
|
|
i++;
|
|
break;
|
|
case '--terminal':
|
|
isTerminal = true;
|
|
id = args[i + 1];
|
|
i++;
|
|
break;
|
|
case '--terminal-admin':
|
|
setEnvTerminalAdmin();
|
|
isTerminal = true;
|
|
id = args[i + 1];
|
|
i++;
|
|
break;
|
|
case '--password':
|
|
password = args[i + 1];
|
|
i++;
|
|
break;
|
|
case '--without-password':
|
|
loginMethod = 'consent';
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
if (id != null) {
|
|
connect(context, id,
|
|
isFileTransfer: isFileTransfer,
|
|
isViewCamera: isViewCamera,
|
|
isTerminal: isTerminal,
|
|
loginMethod: loginMethod,
|
|
password: password);
|
|
}
|
|
}
|
|
}
|