diff --git a/flutter/lib/common/widgets/peer_card.dart b/flutter/lib/common/widgets/peer_card.dart index bc4724e41..279af791b 100644 --- a/flutter/lib/common/widgets/peer_card.dart +++ b/flutter/lib/common/widgets/peer_card.dart @@ -1,6 +1,7 @@ import 'package:contextmenu/contextmenu.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_hbb/consts.dart'; import 'package:get/get.dart'; import '../../common.dart'; @@ -161,13 +162,7 @@ class _PeerCardState extends State<_PeerCard> mainAxisAlignment: MainAxisAlignment.center, children: [ Row(children: [ - Padding( - padding: const EdgeInsets.fromLTRB(0, 4, 4, 4), - child: CircleAvatar( - radius: 5, - backgroundColor: peer.online - ? Colors.green - : Colors.yellow)), + getOnline(4, peer.online), Expanded( child: Text( alias.isEmpty ? formatID(peer.id) : alias, @@ -261,13 +256,7 @@ class _PeerCardState extends State<_PeerCard> children: [ Expanded( child: Row(children: [ - Padding( - padding: const EdgeInsets.fromLTRB(0, 4, 8, 4), - child: CircleAvatar( - radius: 5, - backgroundColor: peer.online - ? Colors.green - : Colors.yellow)), + getOnline(4, peer.online), Expanded( child: Text( peer.alias.isEmpty ? formatID(peer.id) : peer.alias, @@ -1001,3 +990,13 @@ void _rdpDialog(String id) async { ); }); } + +Widget getOnline(int rightMargin, bool online) { + return Tooltip( + message: translate(online ? 'Online' : 'Offline'), + waitDuration: const Duration(seconds: 1), + child: Padding( + padding: const EdgeInsets.fromLTRB(0, 4, 8, 4), + child: CircleAvatar( + radius: 3, backgroundColor: online ? Colors.green : kColorWarn))); +} diff --git a/flutter/lib/consts.dart b/flutter/lib/consts.dart index ff15173d3..ccacab5fb 100644 --- a/flutter/lib/consts.dart +++ b/flutter/lib/consts.dart @@ -11,6 +11,8 @@ const String kAppTypeDesktopPortForward = "port forward"; const String kTabLabelHomePage = "Home"; const String kTabLabelSettingPage = "Settings"; +const Color kColorWarn = Color.fromARGB(255, 245, 133, 59); + const int kMobileDefaultDisplayWidth = 720; const int kMobileDefaultDisplayHeight = 1280; diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index cdd4cc286..07246a916 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -5,6 +5,7 @@ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter_hbb/common/widgets/address_book.dart'; +import 'package:flutter_hbb/consts.dart'; import 'package:get/get.dart'; import 'package:url_launcher/url_launcher_string.dart'; @@ -13,6 +14,7 @@ import '../../common/formatter/id_formatter.dart'; import '../../common/widgets/peer_tab_page.dart'; import '../../common/widgets/peers_view.dart'; import '../../models/platform_model.dart'; +import '../widgets/button.dart'; /// Connection page for connecting to a remote peer. class ConnectionPage extends StatefulWidget { @@ -108,10 +110,6 @@ class _ConnectionPageState extends State { /// UI for the remote ID TextField. /// Search for a peer and connect to it if the id exists. Widget _buildRemoteIDTextField(BuildContext context) { - RxBool ftHover = false.obs; - RxBool ftPressed = false.obs; - RxBool connHover = false.obs; - RxBool connPressed = false.obs; RxBool inputFocused = false.obs; FocusNode focusNode = FocusNode(); focusNode.addListener(() { @@ -190,87 +188,17 @@ class _ConnectionPageState extends State { child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ - Obx(() => InkWell( - onTapDown: (_) => ftPressed.value = true, - onTapUp: (_) => ftPressed.value = false, - onTapCancel: () => ftPressed.value = false, - onHover: (value) => ftHover.value = value, - onTap: () { - onConnect(isFileTransfer: true); - }, - child: Container( - height: 27, - alignment: Alignment.center, - decoration: BoxDecoration( - color: ftPressed.value - ? MyTheme.accent - : Colors.transparent, - border: Border.all( - color: ftPressed.value - ? MyTheme.accent - : ftHover.value - ? MyTheme.hoverBorder - : MyTheme.border, - ), - borderRadius: BorderRadius.circular(5), - ), - child: Text( - translate( - "Transfer File", - ), - style: TextStyle( - fontSize: 12, - color: ftPressed.value - ? Theme.of(context).backgroundColor - : Theme.of(context) - .textTheme - .titleLarge - ?.color), - ).marginSymmetric(horizontal: 12), - ), - )), + Button( + isOutline: true, + onTap: () { + onConnect(isFileTransfer: true); + }, + text: "Transfer File", + ), const SizedBox( width: 17, ), - Obx( - () => InkWell( - onTapDown: (_) => connPressed.value = true, - onTapUp: (_) => connPressed.value = false, - onTapCancel: () => connPressed.value = false, - onHover: (value) => connHover.value = value, - onTap: onConnect, - child: ConstrainedBox( - constraints: BoxConstraints( - minWidth: 80.0, - ), - child: Container( - height: 27, - decoration: BoxDecoration( - color: connPressed.value - ? MyTheme.accent - : MyTheme.button, - border: Border.all( - color: connPressed.value - ? MyTheme.accent - : connHover.value - ? MyTheme.hoverBorder - : MyTheme.button, - ), - borderRadius: BorderRadius.circular(5), - ), - child: Center( - child: Text( - translate( - "Connect", - ), - style: TextStyle( - fontSize: 12, - color: Theme.of(context).backgroundColor), - ), - ).marginSymmetric(horizontal: 12), - )), - ), - ), + Button(onTap: onConnect, text: "Connect"), ], ), ) @@ -302,7 +230,11 @@ class _ConnectionPageState extends State { width: 8, decoration: BoxDecoration( borderRadius: BorderRadius.circular(20), - color: svcStopped.value ? Colors.redAccent : Colors.green, + color: svcStopped.value || svcStatusCode.value == 0 + ? kColorWarn + : (svcStatusCode.value == 1 + ? Color.fromARGB(255, 50, 190, 166) + : Color.fromARGB(255, 224, 79, 95)), ), ).paddingSymmetric(horizontal: 12.0); if (svcStopped.value) { diff --git a/flutter/lib/desktop/pages/desktop_home_page.dart b/flutter/lib/desktop/pages/desktop_home_page.dart index 6c4af5cf8..d238a5690 100644 --- a/flutter/lib/desktop/pages/desktop_home_page.dart +++ b/flutter/lib/desktop/pages/desktop_home_page.dart @@ -26,6 +26,7 @@ class _DesktopHomePageState extends State with TrayListener, WindowListener, AutomaticKeepAliveClientMixin { @override bool get wantKeepAlive => true; + var updateUrl = ''; @override void onWindowClose() async { @@ -74,6 +75,7 @@ class _DesktopHomePageState extends State buildTip(context), buildIDBoard(context), buildPasswordBoard(context), + buildHelpCards(), ], ), ), @@ -293,6 +295,46 @@ class _DesktopHomePageState extends State ); } + Widget buildHelpCards() { + if (Platform.isWindows) { + if (!bind.mainIsInstalled()) { + return buildInstallCard(); + } else if (bind.mainIsInstalledLowerVersion()) { + return buildUpgradeCard(); + } + } + if (updateUrl.isNotEmpty) { + return buildUpdateCard(); + } + if (Platform.isMacOS) {} + if (bind.mainIsInstalledLowerVersion()) {} + return Container(); + } + + Widget buildUpdateCard() { + return Container(); + } + + Widget buildUpgradeCard() { + return Container(); + } + + Widget buildInstallCard() { + return Container( + margin: EdgeInsets.only(top: 20), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + translate("install_tip"), + style: TextStyle(fontWeight: FontWeight.normal, fontSize: 19), + ), + ], + ), + ); + } + @override void onTrayMenuItemClick(MenuItem menuItem) { debugPrint('click ${menuItem.key}'); @@ -310,6 +352,10 @@ class _DesktopHomePageState extends State @override void initState() { super.initState(); + Timer(const Duration(seconds: 5), () async { + updateUrl = await bind.mainGetSoftwareUpdateUrl(); + if (updateUrl.isNotEmpty) setState(() {}); + }); trayManager.addListener(this); windowManager.addListener(this); rustDeskWinManager.setMethodHandler((call, fromWindowId) async { diff --git a/flutter/lib/desktop/pages/desktop_setting_page.dart b/flutter/lib/desktop/pages/desktop_setting_page.dart index ec386a8e2..60da78856 100644 --- a/flutter/lib/desktop/pages/desktop_setting_page.dart +++ b/flutter/lib/desktop/pages/desktop_setting_page.dart @@ -4,6 +4,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_hbb/common.dart'; +import 'package:flutter_hbb/consts.dart'; import 'package:flutter_hbb/desktop/pages/desktop_home_page.dart'; import 'package:flutter_hbb/models/platform_model.dart'; import 'package:flutter_hbb/models/server_model.dart'; @@ -474,7 +475,7 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin { _OptionCheckBox(context, 'Deny remote access', 'stop-service', checkedIcon: const Icon( Icons.warning_amber_rounded, - color: Color.fromARGB(255, 255, 204, 0), + color: kColorWarn, ), enabled: enabled), Offstage( diff --git a/flutter/lib/desktop/widgets/button.dart b/flutter/lib/desktop/widgets/button.dart new file mode 100644 index 000000000..6fcf73836 --- /dev/null +++ b/flutter/lib/desktop/widgets/button.dart @@ -0,0 +1,73 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import '../../common.dart'; + +class Button extends StatefulWidget { + GestureTapCallback onTap; + String text; + double? minWidth; + bool isOutline; + + Button({ + Key? key, + this.minWidth, + this.isOutline = false, + required this.onTap, + required this.text, + }) : super(key: key); + + @override + State