diff --git a/lib/common.dart b/lib/common.dart index 2cf3a9a24..6461b8319 100644 --- a/lib/common.dart +++ b/lib/common.dart @@ -51,6 +51,10 @@ class DialogManager{ static void register(BuildContext dialogContext){ _dialogContext = dialogContext; } + + static void drop(){ + _dialogContext = null; + } } typedef BuildAlertDialog = Tuple3> Function( @@ -83,7 +87,7 @@ Future showAlertDialog(BuildAlertDialog build, DialogManager.register(context); return dialog; }); - DialogManager.reset(); + DialogManager.drop(); return res; } diff --git a/lib/main.dart b/lib/main.dart index 9c6e152be..e82bf411c 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -4,9 +4,9 @@ import 'package:provider/provider.dart'; import 'package:firebase_analytics/firebase_analytics.dart'; import 'package:firebase_analytics/observer.dart'; import 'package:firebase_core/firebase_core.dart'; -import 'model.dart'; -import 'home_page.dart'; -import 'server_page.dart'; +import 'models/model.dart'; +import 'pages/home_page.dart'; +import 'pages/server_page.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -37,7 +37,7 @@ class App extends StatelessWidget { primarySwatch: Colors.blue, visualDensity: VisualDensity.adaptivePlatformDensity, ), - home: HomePage(title: 'RustDesk'), + home: HomePage(), routes: { "server_page": (context) => ServerPage(), }, diff --git a/lib/model.dart b/lib/models/model.dart similarity index 99% rename from lib/model.dart rename to lib/models/model.dart index bf73ab802..e9bc7c061 100644 --- a/lib/model.dart +++ b/lib/models/model.dart @@ -8,7 +8,7 @@ import 'dart:ui' as ui; import 'package:flutter/material.dart'; import 'package:tuple/tuple.dart'; import 'dart:async'; -import 'common.dart'; +import '../common.dart'; import 'native_model.dart' if (dart.library.html) 'web_model.dart'; class FfiModel with ChangeNotifier { diff --git a/lib/native_model.dart b/lib/models/native_model.dart similarity index 99% rename from lib/native_model.dart rename to lib/models/native_model.dart index c8fb81c58..730a0aef7 100644 --- a/lib/native_model.dart +++ b/lib/models/native_model.dart @@ -7,7 +7,7 @@ import 'package:device_info/device_info.dart'; import 'package:package_info/package_info.dart'; import 'package:external_path/external_path.dart'; import 'package:flutter/services.dart'; -import 'common.dart'; +import '../common.dart'; class RgbaFrame extends Struct { @Uint32() diff --git a/lib/web_model.dart b/lib/models/web_model.dart similarity index 99% rename from lib/web_model.dart rename to lib/models/web_model.dart index 7c1eadd4b..778db6d97 100644 --- a/lib/web_model.dart +++ b/lib/models/web_model.dart @@ -3,7 +3,7 @@ import 'dart:js' as js; import 'package:flutter/cupertino.dart'; import 'dart:convert'; -import 'common.dart'; +import '../common.dart'; import 'dart:html'; import 'dart:async'; diff --git a/lib/home_page.dart b/lib/pages/home_page.dart similarity index 75% rename from lib/home_page.dart rename to lib/pages/home_page.dart index 460150a5a..d2dd9b718 100644 --- a/lib/home_page.dart +++ b/lib/pages/home_page.dart @@ -1,22 +1,89 @@ import 'package:flutter/material.dart'; +import 'package:flutter_hbb/pages/server_page.dart'; import 'package:provider/provider.dart'; import 'package:tuple/tuple.dart'; import 'package:url_launcher/url_launcher.dart'; import 'dart:async'; -import 'common.dart'; -import 'model.dart'; +import '../common.dart'; +import '../models/model.dart'; import 'remote_page.dart'; -class HomePage extends StatefulWidget { - HomePage({Key? key, required this.title}) : super(key: key); +abstract class PageShape extends Widget { + final String title = ""; + final Icon icon = Icon(null); + final List appBarActions = []; +} - final String title; +class HomePage extends StatefulWidget { + HomePage({Key? key}) : super(key: key); @override _HomePageState createState() => _HomePageState(); } class _HomePageState extends State { + var _selectedIndex = 0; + final List _pages = [ConnectionPage(), ServerPage()]; + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: MyTheme.grayBg, + appBar: AppBar( + centerTitle: true, + title: Text("RustDesk"), + actions: _pages.elementAt(_selectedIndex).appBarActions, + ), + bottomNavigationBar: BottomNavigationBar( + 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(() { + _selectedIndex = index; + }), + ), + body: _pages.elementAt(_selectedIndex), + ); + } +} + +class ConnectionPage extends StatefulWidget implements PageShape { + ConnectionPage({Key? key}) : super(key: key); + + @override + final icon = Icon(Icons.connected_tv); + + @override + final title = translate("Connection"); + + @override + final appBarActions = [ + PopupMenuButton( + itemBuilder: (context) => [ + PopupMenuItem( + child: Text(translate('ID Server')), value: 'id_server'), + PopupMenuItem( + child: Text(translate('About') + ' RustDesk'), value: 'about') + ], + onSelected: (value) { + if (value == 'id_server') { + showServer(); + } else if (value == 'about') { + showAbout(); + } + }) + ]; + + @override + _ConnectionPageState createState() => _ConnectionPageState(); +} + +class _ConnectionPageState extends State { final _idController = TextEditingController(); var _updateUrl = ''; var _menuPos; @@ -36,83 +103,18 @@ class _HomePageState extends State { Widget build(BuildContext context) { Provider.of(context); if (_idController.text.isEmpty) _idController.text = FFI.getId(); - // This method is rerun every time setState is called - return Scaffold( - backgroundColor: MyTheme.grayBg, - appBar: AppBar( - centerTitle: true, - actions: [ - Ink( - child: InkWell( - child: Padding( - padding: const EdgeInsets.all(12), - child: Icon(Icons.more_vert)), - onTapDown: (e) { - var x = e.globalPosition.dx; - var y = e.globalPosition.dy; - this._menuPos = RelativeRect.fromLTRB(x, y, x, y); - }, - onTap: () { - List> items = []; - items.add(PopupMenuItem( - child: Text(translate('ID Server')), - value: 'id_server')); - if (isAndroid) { - items.add(PopupMenuItem( - child: Text(translate('Share My Screen')), - value: 'server')); - } - items.add(PopupMenuItem( - child: Text(translate('About') + ' RustDesk'), - value: 'about')); - () async { - var value = await showMenu( - context: context, - position: this._menuPos, - items: items, - elevation: 8, - ); - if (value == 'id_server') { - showServer(context); - } else if (value == 'server') { - Navigator.pushNamed(context, "server_page"); - } else if (value == 'about') { - showAbout(context); - } - }(); - })) - ], - title: Text(widget.title), - ), - body: SingleChildScrollView( - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - mainAxisSize: MainAxisSize.max, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - _updateUrl.isEmpty - ? SizedBox(height: 0) - : InkWell( - onTap: () async { - final url = _updateUrl + '.apk'; - if (await canLaunch(url)) { - await launch(url); - } - }, - child: Container( - alignment: AlignmentDirectional.center, - width: double.infinity, - color: Colors.pinkAccent, - padding: EdgeInsets.symmetric(vertical: 12), - child: Text(translate('Download new version'), - style: TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold)))), - getSearchBarUI(), - Container(height: 12), - getPeers(), - ]), - )); + return SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + getUpdateUI(), + getSearchBarUI(), + Container(height: 12), + getPeers(), + ]), + ); } void onConnect() { @@ -138,6 +140,26 @@ class _HomePageState extends State { } } + Widget getUpdateUI() { + return _updateUrl.isEmpty + ? SizedBox(height: 0) + : InkWell( + onTap: () async { + final url = _updateUrl + '.apk'; + if (await canLaunch(url)) { + await launch(url); + } + }, + child: Container( + alignment: AlignmentDirectional.center, + width: double.infinity, + color: Colors.pinkAccent, + padding: EdgeInsets.symmetric(vertical: 12), + child: Text(translate('Download new version'), + style: TextStyle( + color: Colors.white, fontWeight: FontWeight.bold)))); + } + Widget getSearchBarUI() { if (!FFI.ffiModel.initialized) { return Container(); @@ -305,7 +327,7 @@ class _HomePageState extends State { } } -void showServer(BuildContext context) { +void showServer() { final formKey = GlobalKey(); final id0 = FFI.getByName('option', 'custom-rendezvous-server'); final relay0 = FFI.getByName('option', 'relay-server'); @@ -355,7 +377,7 @@ void showServer(BuildContext context) { TextButton( style: flatButtonStyle, onPressed: () { - Navigator.pop(context); + DialogManager.reset(); }, child: Text(translate('Cancel')), ), @@ -373,7 +395,7 @@ void showServer(BuildContext context) { 'option', '{"name": "relay-server", "value": "$relay"}'); if (key != key0) FFI.setByName('option', '{"name": "key", "value": "$key"}'); - Navigator.pop(context); + DialogManager.reset(); } }, child: Text(translate('OK')), @@ -382,7 +404,7 @@ void showServer(BuildContext context) { )); } -Future showAbout(BuildContext context) async { +Future showAbout() async { var version = await FFI.getVersion(); showAlertDialog( (setState) => Tuple3( diff --git a/lib/remote_page.dart b/lib/pages/remote_page.dart similarity index 99% rename from lib/remote_page.dart rename to lib/pages/remote_page.dart index 128ede27a..b07bff520 100644 --- a/lib/remote_page.dart +++ b/lib/pages/remote_page.dart @@ -8,9 +8,9 @@ import 'dart:ui' as ui; import 'dart:async'; import 'package:tuple/tuple.dart'; import 'package:wakelock/wakelock.dart'; -import 'common.dart'; -import 'gestures.dart'; -import 'model.dart'; +import '../common.dart'; +import '../gestures.dart'; +import '../models/model.dart'; final initText = '\1' * 1024; diff --git a/lib/server_page.dart b/lib/pages/server_page.dart similarity index 89% rename from lib/server_page.dart rename to lib/pages/server_page.dart index eaf6c92a7..269536d4e 100644 --- a/lib/server_page.dart +++ b/lib/pages/server_page.dart @@ -1,56 +1,59 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_hbb/main.dart'; -import 'package:flutter_hbb/model.dart'; +import 'package:flutter_hbb/models/model.dart'; import 'package:provider/provider.dart'; -import 'common.dart'; -import 'model.dart'; +import '../common.dart'; +import 'home_page.dart'; +import '../models/model.dart'; + +class ServerPage extends StatelessWidget implements PageShape { + @override + final title = "Share Screen"; + + @override + final icon = Icon(Icons.mobile_screen_share); + + @override + final appBarActions = [ + PopupMenuButton( + itemBuilder: (context) { + return [ + PopupMenuItem( + child: Text(translate("Change ID")), + value: "changeID", + enabled: false, + ), + PopupMenuItem( + child: Text("Set your own password"), + value: "changePW", + enabled: false, + ) + ]; + }, + onSelected: (value) => debugPrint("PopupMenuItem onSelected:$value")) + ]; -class ServerPage extends StatelessWidget { @override Widget build(BuildContext context) { checkService(); return ChangeNotifierProvider.value( - value: FFI.serverModel, - child: Scaffold( - backgroundColor: MyTheme.grayBg, - appBar: AppBar( - centerTitle: true, - title: const Text("Share My Screen"), - actions: [ - PopupMenuButton( - itemBuilder: (context) { - return [ - PopupMenuItem( - child: Text(translate("Change ID")), - value: "changeID", - enabled: false, - ), - PopupMenuItem( - child: Text("Set your own password"), - value: "changePW", - enabled: false, - ) - ]; - }, - onSelected: (value) => - debugPrint("PopupMenuItem onSelected:$value")) - ], - ), - body: SingleChildScrollView( - child: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - ServerInfo(), - PermissionChecker(), - ConnectionManager(), - SizedBox.fromSize(size: Size(0, 15.0)), // Bottom padding - ], - ), - ), - ))); + value: FFI.serverModel, + child: SingleChildScrollView( + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + ServerInfo(), + PermissionChecker(), + ConnectionManager(), + SizedBox.fromSize(size: Size(0, 15.0)), // Bottom padding + ], + ), + ), + ), + ); } }