From e0fd6981018091a31bae2e883900306ebffc1ce1 Mon Sep 17 00:00:00 2001 From: 21pages Date: Tue, 11 Mar 2025 16:29:02 +0800 Subject: [PATCH] opt dropdown button of connection page (#11086) * Use menu style of the peer card * Add margin between connection button and dropdown button * Use thinner icon Signed-off-by: 21pages --- flutter/assets/more.ttf | Bin 0 -> 1620 bytes flutter/lib/common.dart | 3 + .../lib/desktop/pages/connection_page.dart | 100 +++++++++++------- .../lib/desktop/pages/view_camera_page.dart | 2 +- flutter/pubspec.yaml | 3 + 5 files changed, 71 insertions(+), 37 deletions(-) create mode 100644 flutter/assets/more.ttf diff --git a/flutter/assets/more.ttf b/flutter/assets/more.ttf new file mode 100644 index 0000000000000000000000000000000000000000..3b01435df3ac47b3db64ea4196935c064dae987b GIT binary patch literal 1620 zcmd^9Jx>%t7=C7VIc^U{0*N9T*$_k{&Y;3J8G+J1gSlAdFdt+kINCE|xQVKq^I~P&-2fmki=Xsy^W8Rsa8wdbRs6ofT z*u>Ns>)z3ufH*~V^72G~ZurQB&$RE;zMl8&%G%)T_q2a)SZ(PEl_xj(4VZjiTeT-thpD&^UW6|onc^taQteA{zc zo({jHpZQv;5>z9CDZ=flOUDqVhsc0AsV>wUF{>e2gxkfkrT|+(4dpuMXnUj7w~S?Ts7nKfc^zFhW&jS znp{w|#5MTEfxd(ilPdNSS((+xnY$%#pev4HYrv|x#r-FmcCrHq+5i78d*TB)td1c* zD|u41ldmA}d5rW2ylJgKThEBd9Wcd+=oCjpqi7b#YH88hVTvg+k#5iErrx;u$UKzM zvSvqXdh?d3k! zso#Vikv|(ccH|VSnI&sBANa+7hquqOVqQ-BY=-$ ztfL+FIHOCLhs(@xhxgy?X-0>rGEUaCFvy2(U`N&%qx?AX-)^c{;A%Pc7_lRZBV;9y zXjJv*uoIWq;s=zzIo8QDI*W3gRlyMY`K#}z9-oc(>B)yD5&8b@CYsQM4#NvV`G(>* D@=?y^ literal 0 HcmV?d00001 diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index bf769d494..5d43d7ae1 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -108,6 +108,8 @@ class IconFont { static const _family2 = 'PeerSearchbar'; static const _family3 = 'AddressBook'; static const _family4 = 'DeviceGroup'; + static const _family5 = 'More'; + IconFont._(); static const IconData max = IconData(0xe606, fontFamily: _family1); @@ -123,6 +125,7 @@ class IconFont { IconData(0xe623, fontFamily: _family4); static const IconData deviceGroupFill = IconData(0xe748, fontFamily: _family4); + static const IconData more = IconData(0xe609, fontFamily: _family5); } class ColorThemeExtension extends ThemeExtension { diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index 8efc355f3..608960378 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -2,10 +2,12 @@ import 'dart:async'; import 'dart:convert'; +import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter_hbb/common/widgets/connection_page_title.dart'; import 'package:flutter_hbb/consts.dart'; +import 'package:flutter_hbb/desktop/widgets/popup_menu.dart'; import 'package:flutter_hbb/models/state_model.dart'; import 'package:get/get.dart'; import 'package:url_launcher/url_launcher_string.dart'; @@ -17,6 +19,7 @@ import '../../common/formatter/id_formatter.dart'; import '../../common/widgets/peer_tab_page.dart'; import '../../common/widgets/autocomplete.dart'; import '../../models/platform_model.dart'; +import '../../desktop/widgets/material_mod_popup_menu.dart' as mod_menu; class OnlineStatusWidget extends StatefulWidget { const OnlineStatusWidget({Key? key, this.onSvcStatusChanged}) @@ -211,6 +214,8 @@ class _ConnectionPageState extends State // https://github.com/flutter/flutter/issues/157244 Iterable _autocompleteOpts = []; + final _menuOpen = false.obs; + @override void initState() { super.initState(); @@ -513,7 +518,7 @@ class _ConnectionPageState extends State child: Text(translate("Connect")), ), ), - const SizedBox(width: 3), + const SizedBox(width: 8), Container( height: 28.0, width: 28.0, @@ -522,41 +527,64 @@ class _ConnectionPageState extends State borderRadius: BorderRadius.circular(8), ), child: Center( - child: MenuAnchor( - builder: (context, controller, builder) { - return IconButton( - padding: EdgeInsets.zero, - constraints: BoxConstraints(), - visualDensity: VisualDensity.compact, - icon: controller.isOpen - ? const Icon(Icons.keyboard_arrow_up) - : const Icon(Icons.keyboard_arrow_down), - onPressed: () { - setState(() { - if (controller.isOpen) { - controller.close(); - } else { - controller.open(); - } - }); - }, - ); - }, - menuChildren: [ - MenuItemButton( - onPressed: () { - onConnect(isFileTransfer: true); - }, - child: Text(translate('Transfer file')), - ), - MenuItemButton( - onPressed: () { - onConnect(isViewCamera: true); - }, - child: Text(translate('View camera')), - ), - ], - ), + child: Obx(() { + var offset = Offset(0, 0); + return InkWell( + child: _menuOpen.value + ? Transform.rotate( + angle: pi, + child: Icon(IconFont.more, size: 14), + ) + : Icon(IconFont.more, size: 14), + onTapDown: (e) { + offset = e.globalPosition; + }, + onTap: () async { + _menuOpen.value = true; + final x = offset.dx; + final y = offset.dy; + await mod_menu + .showMenu( + context: context, + position: RelativeRect.fromLTRB(x, y, x, y), + items: [ + ( + 'Transfer file', + () => onConnect(isFileTransfer: true) + ), + ( + 'View camera', + () => onConnect(isViewCamera: true) + ), + ] + .map((e) => MenuEntryButton( + childBuilder: (TextStyle? style) => Text( + translate(e.$1), + style: style, + ), + proc: () => e.$2(), + padding: EdgeInsets.symmetric( + horizontal: kDesktopMenuPadding.left), + dismissOnClicked: true, + )) + .map((e) => e.build( + context, + const MenuConfig( + commonColor: + CustomPopupMenuTheme.commonColor, + height: CustomPopupMenuTheme.height, + dividerHeight: CustomPopupMenuTheme + .dividerHeight))) + .expand((i) => i) + .toList(), + elevation: 8, + ) + .then((_) { + _menuOpen.value = false; + }); + }, + ); + }), ), ), ]), diff --git a/flutter/lib/desktop/pages/view_camera_page.dart b/flutter/lib/desktop/pages/view_camera_page.dart index b06dc86c5..d86114014 100644 --- a/flutter/lib/desktop/pages/view_camera_page.dart +++ b/flutter/lib/desktop/pages/view_camera_page.dart @@ -229,7 +229,7 @@ class _ViewCameraPageState extends State // https://github.com/flutter/flutter/issues/64935 super.dispose(); - debugPrint("REMOTE PAGE dispose session $sessionId ${widget.id}"); + debugPrint("VIEW CAMERA PAGE dispose session $sessionId ${widget.id}"); _ffi.textureModel.onViewCameraPageDispose(closeSession); if (closeSession) { // ensure we leave this session, this is a double check diff --git a/flutter/pubspec.yaml b/flutter/pubspec.yaml index a9aae014e..d16365fa5 100644 --- a/flutter/pubspec.yaml +++ b/flutter/pubspec.yaml @@ -164,6 +164,9 @@ flutter: - family: DeviceGroup fonts: - asset: assets/device_group.ttf + - family: More + fonts: + - asset: assets/more.ttf # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware.