From bb64690ac97ca3360c3c134718f95f53c6257a8d Mon Sep 17 00:00:00 2001 From: 21pages Date: Wed, 24 Aug 2022 11:01:58 +0800 Subject: [PATCH] optimize style of peer card Signed-off-by: 21pages --- flutter/assets/peer_searchbar.ttf | Bin 0 -> 1940 bytes flutter/lib/common.dart | 17 +- .../lib/desktop/pages/connection_page.dart | 338 +++++++++--------- .../lib/desktop/pages/desktop_home_page.dart | 36 +- flutter/lib/desktop/widgets/peer_widget.dart | 6 +- .../lib/desktop/widgets/peercard_widget.dart | 265 ++++++++------ .../lib/desktop/widgets/tabbar_widget.dart | 4 +- flutter/pubspec.yaml | 7 +- 8 files changed, 363 insertions(+), 310 deletions(-) create mode 100644 flutter/assets/peer_searchbar.ttf diff --git a/flutter/assets/peer_searchbar.ttf b/flutter/assets/peer_searchbar.ttf new file mode 100644 index 0000000000000000000000000000000000000000..7f87e48ce40bbffe890bb21bcbbcab31e0004f82 GIT binary patch literal 1940 zcmd^A&2Jk;6o0e3UI*Ja33Z&dNX}vr8>N+#SgsSb!3|Af%N61y4G|I%&c7T$@GxK}D z_j_;N%+9Wf5s{Z#B+^Lc!b|6r4+dW+V&h=vp1&|0pSYU+3igMv7xOi>QAvN_2m3Gd zcS_aO;tzcp=*4$o7s{Gicw*(7Poceyo-BiK?}%>$UqgSgTr)5E_#$tAVyoSv1=Cx?qy&Y$qp+?#6Bh$mU~b57Tibn z%zmdhL!>}1yBfIu+g>Qn6zImm*1;X?JV^YRT2SyB?>B)jXmy*%I@az^+BAFB(Z39q zD^6m@j=@X7gep-U34E0{PN6fy!*{^%g7bBwXDUkHSRcuGh_SU4JqMiOJmv1GhI*dGkIWw$JjB@>Zw zH;YEXa$tbDSP+wMO9J>SgQQX;Xm_WqihNT_Q^w@1%pH?kR9hY%Yc8`^ev z2Ubt1&~@ae_(?xTJO7^g5!n2m^RbJLI9MPzJ?>x;eAvMf@Q{OD_+rK#EQ7bcM9AZz z6Ex%SUSw?WH%WQ~o(R3^V20;=*}($&>8gW8@LxMv0{+p#E(+3b4wk{+b+Cu#*`p5j zQiSEF3{5q)g0i%#RPuVgsMpQTJgb$KtE$m4JM+9|G%I>t8I6r}sEk(Ej82;7N-1ud zMWtxyH6@LFTD7Vx4MV@E<;_^xG#jUfhxt03kLC3mO_4zwsbpd-kU~qeim^g@(y5MX z&PVehdlu>vEmIYd#zWr2(eqFn)P#;_Q)rZ8xMYV_8K~-(@^CdxTES{@)M26`1>HcV z8c^D)PeUbDURX5$xTf)@?}f-58n?m_y7O^ literal 0 HcmV?d00001 diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index 9944d6884..643705d69 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -41,15 +41,18 @@ late final iconRestart = MemoryImage(Uint8List.fromList(base64Decode( 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAB7BAAAewQHDaVRTAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAbhJREFUWIXVlrFqFGEUhb+7UYxaWCQKlrKKxaZSQVGDJih2tj6MD2DnMwiWvoAIRnENIpZiYxEro6IooiS7SPwsMgNLkk3mjmYmnmb45/73nMNwz/x/qH3gMu2gH6rAU+Blw+Lngau4jpmGxVF7qp1iPWjaQKnZ2WnXbuP/NqAeUPc3ZkA9XDwvqc+BVWCgPlJ7tRwUKThZce819b46VH+pfXVRXVO/q2cSul3VOgZUl0ejq86r39TXI8mqZKDuDEwCw3IREQvAbWAGmMsQZQ0sAl3gHPB1Q+0e8BuYzRDuy2yOiFVgaUxtRf0ETGc4syk4rc6PqU0Cx9j8Zf6dAeAK8Fi9sUXtFjABvEgxJlNwRP2svlNPjbw/q35U36oTFbnyMSwabxb/gB/qA3VBHagrauV7RW0DRfP1IvMlXqkXkhz1DYyQTKtHa/Z2VVMx3IiI+PI3/bCHjuOpFrSnAMpL6QfgTcMGesDx0kBr2BMzsNyi/vtQu8CJlgwsRbZDnWP90NkKaxHxJMOXMqAeAn5u0ydwMCKGY+qbkB3C2W3EKWoXk5zVoHbUZ+6Mh7tl4G4F8RJ3qvL+AfV3r5Vdpj70AAAAAElFTkSuQmCC'))); class IconFont { - static const _family = 'iconfont'; + static const _family1 = 'Tabbar'; + static const _family2 = 'PeerSearchbar'; IconFont._(); - static const IconData max = IconData(0xe606, fontFamily: _family); - static const IconData restore = IconData(0xe607, fontFamily: _family); - static const IconData close = IconData(0xe668, fontFamily: _family); - static const IconData min = IconData(0xe609, fontFamily: _family); - static const IconData add = IconData(0xe664, fontFamily: _family); - static const IconData menu = IconData(0xe628, fontFamily: _family); + static const IconData max = IconData(0xe606, fontFamily: _family1); + static const IconData restore = IconData(0xe607, fontFamily: _family1); + static const IconData close = IconData(0xe668, fontFamily: _family1); + static const IconData min = IconData(0xe609, fontFamily: _family1); + static const IconData add = IconData(0xe664, fontFamily: _family1); + static const IconData menu = IconData(0xe628, fontFamily: _family1); + static const IconData search = IconData(0xe6a4, fontFamily: _family2); + static const IconData round_close = IconData(0xe6ed, fontFamily: _family2); } class ColorThemeExtension extends ThemeExtension { diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index 0b407d227..29219df2a 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -63,70 +63,43 @@ class _ConnectionPageState extends State { mainAxisSize: MainAxisSize.max, crossAxisAlignment: CrossAxisAlignment.start, children: [ - getUpdateUI(), - Row( - children: [ - getSearchBarUI(context), - ], - ).marginOnly(top: 22, left: 22), - SizedBox(height: 12), - Divider( - thickness: 1, - indent: 22, - endIndent: 22, - ), Expanded( - // TODO: move all tab info into _PeerTabbedPage - child: _PeerTabbedPage( - tabs: [ - translate('Recent Sessions'), - translate('Favorites'), - translate('Discovered'), - translate('Address Book') - ], - children: [ - RecentPeerWidget(), - FavoritePeerWidget(), - DiscoveredPeerWidget(), - // AddressBookPeerWidget(), - // FutureBuilder( - // future: getPeers(rType: RemoteType.recently), - // builder: (context, snapshot) { - // if (snapshot.hasData) { - // return snapshot.data!; - // } else { - // return Offstage(); - // } - // }), - // FutureBuilder( - // future: getPeers(rType: RemoteType.favorite), - // builder: (context, snapshot) { - // if (snapshot.hasData) { - // return snapshot.data!; - // } else { - // return Offstage(); - // } - // }), - // FutureBuilder( - // future: getPeers(rType: RemoteType.discovered), - // builder: (context, snapshot) { - // if (snapshot.hasData) { - // return snapshot.data!; - // } else { - // return Offstage(); - // } - // }), - FutureBuilder( - future: buildAddressBook(context), - builder: (context, snapshot) { - if (snapshot.hasData) { - return snapshot.data!; - } else { - return Offstage(); - } - }), - ], - ).marginSymmetric(horizontal: 6)), + child: Column( + children: [ + getUpdateUI(), + Row( + children: [ + getSearchBarUI(context), + ], + ).marginOnly(top: 22), + SizedBox(height: 12), + Divider(), + Expanded( + child: _PeerTabbedPage( + tabs: [ + translate('Recent Sessions'), + translate('Favorites'), + translate('Discovered'), + translate('Address Book') + ], + children: [ + RecentPeerWidget(), + FavoritePeerWidget(), + DiscoveredPeerWidget(), + FutureBuilder( + future: buildAddressBook(context), + builder: (context, snapshot) { + if (snapshot.hasData) { + return snapshot.data!; + } else { + return Offstage(); + } + }), + ], + )), + ], + ).marginSymmetric(horizontal: 22), + ), Divider(), SizedBox(height: 50, child: Obx(() => buildStatus())) .paddingSymmetric(horizontal: 12.0) @@ -193,7 +166,7 @@ class _ConnectionPageState extends State { }); var w = Container( width: 320 + 20 * 2, - padding: EdgeInsets.only(left: 20, right: 20, bottom: 22, top: 24), + padding: EdgeInsets.fromLTRB(20, 24, 20, 22), decoration: BoxDecoration( color: MyTheme.color(context).bg, borderRadius: const BorderRadius.all(Radius.circular(13)), @@ -977,67 +950,57 @@ class _PeerTabbedPage extends StatefulWidget { class _PeerTabbedPageState extends State<_PeerTabbedPage> with SingleTickerProviderStateMixin { - late TabController _tabController; + late PageController _pageController = PageController(); RxInt _tabIndex = 0.obs; @override void initState() { super.initState(); - _tabController = - TabController(vsync: this, length: super.widget.tabs.length); - _tabController.addListener(_handleTabSelection); } // hard code for now - void _handleTabSelection() { - if (_tabController.indexIsChanging) { - // reset search text - peerSearchText.value = ""; - peerSearchTextController.clear(); - _tabIndex.value = _tabController.index; - switch (_tabController.index) { - case 0: - bind.mainLoadRecentPeers(); - break; - case 1: - bind.mainLoadFavPeers(); - break; - case 2: - bind.mainDiscover(); - break; - case 3: - break; - } + void _handleTabSelection(int index) { + // reset search text + peerSearchText.value = ""; + peerSearchTextController.clear(); + _tabIndex.value = index; + _pageController.jumpToPage(index); + switch (index) { + case 0: + bind.mainLoadRecentPeers(); + break; + case 1: + bind.mainLoadFavPeers(); + break; + case 2: + bind.mainDiscover(); + break; + case 3: + break; } } @override void dispose() { - _tabController.dispose(); + _pageController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { - // return DefaultTabController( - // length: 4, - // child: Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // _createTabBar(), - // _createTabBarView(), - // ], - // )); - return Column( + textBaseline: TextBaseline.ideographic, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Row( - children: [ - Expanded(child: _createTabBar(context)), - _createSearchBar(context), - _createPeerViewTypeSwitch(context), - ], + Container( + height: 28, + child: Row( + children: [ + Expanded(child: _createTabBar(context)), + _createSearchBar(context), + _createPeerViewTypeSwitch(context), + ], + ), ), _createTabBarView(), ], @@ -1045,70 +1008,121 @@ class _PeerTabbedPageState extends State<_PeerTabbedPage> } Widget _createTabBar(BuildContext context) { - return TabBar( - isScrollable: true, - indicatorSize: TabBarIndicatorSize.label, - indicatorColor: Colors.transparent, - indicatorWeight: 0.1, - controller: _tabController, - labelPadding: EdgeInsets.zero, - padding: EdgeInsets.only(left: 16), - tabs: super.widget.tabs.asMap().entries.map((t) { - return Obx(() => Container( - padding: EdgeInsets.symmetric(horizontal: 8, vertical: 6), - decoration: BoxDecoration( - color: - _tabIndex.value == t.key ? MyTheme.color(context).bg : null, - borderRadius: BorderRadius.circular(2), - ), - child: Text( - t.value, - style: TextStyle( - height: 1, - color: _tabIndex.value == t.key - ? MyTheme.color(context).text - : MyTheme.color(context).lightText), - ))); + return ListView( + scrollDirection: Axis.horizontal, + shrinkWrap: true, + children: super.widget.tabs.asMap().entries.map((t) { + return Obx(() => GestureDetector( + child: Container( + padding: EdgeInsets.symmetric(horizontal: 8), + decoration: BoxDecoration( + color: _tabIndex.value == t.key + ? MyTheme.color(context).bg + : null, + borderRadius: BorderRadius.circular(2), + ), + child: Align( + alignment: Alignment.center, + child: Text( + t.value, + textAlign: TextAlign.center, + style: TextStyle( + height: 1, + fontSize: 14, + color: _tabIndex.value == t.key + ? MyTheme.color(context).text + : MyTheme.color(context).lightText), + ), + )), + onTap: () => _handleTabSelection(t.key), + )); }).toList()); } Widget _createTabBarView() { return Expanded( - child: TabBarView( - controller: _tabController, children: super.widget.children) - .paddingSymmetric(horizontal: 12.0, vertical: 4.0)); + child: PageView( + controller: _pageController, children: super.widget.children) + .marginSymmetric(vertical: 12)); } _createSearchBar(BuildContext context) { + RxBool focused = false.obs; + FocusNode focusNode = FocusNode(); + focusNode.addListener(() => focused.value = focusNode.hasFocus); + RxBool rowHover = false.obs; + RxBool clearHover = false.obs; return Container( - width: 175, - height: 30, - margin: EdgeInsets.only(right: 16), - decoration: BoxDecoration(color: Colors.white), - child: Obx( - () => TextField( - controller: peerSearchTextController, - onChanged: (searchText) { - peerSearchText.value = searchText; - }, - decoration: InputDecoration( - prefixIcon: Icon( - Icons.search, - size: 20, - ), - contentPadding: EdgeInsets.zero, - hintText: translate("Search ID"), - hintStyle: TextStyle(fontSize: 14), - border: OutlineInputBorder(), - isDense: true, - ), - ), - ), + width: 120, + height: 25, + margin: EdgeInsets.only(right: 13), + decoration: BoxDecoration(color: MyTheme.color(context).bg), + child: Obx(() => Row( + children: [ + Expanded( + child: MouseRegion( + onEnter: (_) => rowHover.value = true, + onExit: (_) => rowHover.value = false, + child: Row( + children: [ + Icon( + IconFont.search, + size: 16, + color: MyTheme.color(context).placeholder, + ).marginSymmetric(horizontal: 4), + Expanded( + child: TextField( + controller: peerSearchTextController, + onChanged: (searchText) { + peerSearchText.value = searchText; + }, + focusNode: focusNode, + textAlign: TextAlign.start, + maxLines: 1, + cursorColor: MyTheme.color(context).lightText, + cursorHeight: 18, + cursorWidth: 1, + style: TextStyle(fontSize: 14), + decoration: InputDecoration( + contentPadding: EdgeInsets.symmetric(vertical: 6), + hintText: + focused.value ? null : translate("Search ID"), + hintStyle: TextStyle( + fontSize: 14, + color: MyTheme.color(context).placeholder), + border: InputBorder.none, + isDense: true, + ), + ), + ), + ], + ), + ), + ), + Offstage( + offstage: !(peerSearchText.value.isNotEmpty && + (rowHover.value || clearHover.value)), + child: InkWell( + onHover: (value) => clearHover.value = value, + child: Icon( + IconFont.round_close, + size: 16, + color: clearHover.value + ? MyTheme.color(context).text + : MyTheme.color(context).placeholder, + ).marginSymmetric(horizontal: 4), + onTap: () { + peerSearchTextController.clear(); + peerSearchText.value = ""; + }), + ) + ], + )), ); } _createPeerViewTypeSwitch(BuildContext context) { - final activeDeco = BoxDecoration(color: Colors.white); + final activeDeco = BoxDecoration(color: MyTheme.color(context).bg); return Row( children: [ Obx( @@ -1122,8 +1136,10 @@ class _PeerTabbedPageState extends State<_PeerTabbedPage> }, child: Icon( Icons.grid_view_rounded, - size: 20, - color: Colors.black54, + size: 18, + color: peerCardUiType.value == PeerUiType.grid + ? MyTheme.color(context).text + : MyTheme.color(context).lightText, )), ), ), @@ -1138,12 +1154,14 @@ class _PeerTabbedPageState extends State<_PeerTabbedPage> }, child: Icon( Icons.list, - size: 24, - color: Colors.black54, + size: 18, + color: peerCardUiType.value == PeerUiType.list + ? MyTheme.color(context).text + : MyTheme.color(context).lightText, )), ), ), ], - ).paddingOnly(right: 16.0); + ); } } diff --git a/flutter/lib/desktop/pages/desktop_home_page.dart b/flutter/lib/desktop/pages/desktop_home_page.dart index f85cf5b86..12f17c95e 100644 --- a/flutter/lib/desktop/pages/desktop_home_page.dart +++ b/flutter/lib/desktop/pages/desktop_home_page.dart @@ -107,9 +107,10 @@ class _DesktopHomePageState extends State crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( - height: 15, + height: 25, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( translate("ID"), @@ -133,7 +134,7 @@ class _DesktopHomePageState extends State readOnly: true, decoration: InputDecoration( border: InputBorder.none, - contentPadding: EdgeInsets.only(bottom: 8), + contentPadding: EdgeInsets.only(bottom: 18), ), style: TextStyle( fontSize: 22, @@ -239,26 +240,17 @@ class _DesktopHomePageState extends State } }, child: Obx( - () => Container( - decoration: BoxDecoration( - // borderRadius: BorderRadius.circular(10), - shape: BoxShape.circle, - boxShadow: [ - BoxShadow( - color: hover.value - ? MyTheme.color(context).grayBg! - : MyTheme.color(context).bg!, - spreadRadius: 2) - ], - ), - child: Center( - child: Icon( - Icons.more_vert_outlined, - size: 20, - color: hover.value - ? MyTheme.color(context).text - : MyTheme.color(context).lightText, - ), + () => CircleAvatar( + radius: 12, + backgroundColor: hover.value + ? MyTheme.color(context).grayBg! + : MyTheme.color(context).bg!, + child: Icon( + Icons.more_vert_outlined, + size: 20, + color: hover.value + ? MyTheme.color(context).text + : MyTheme.color(context).lightText, ), ), ), diff --git a/flutter/lib/desktop/widgets/peer_widget.dart b/flutter/lib/desktop/widgets/peer_widget.dart index 70df44ab5..fa79db624 100644 --- a/flutter/lib/desktop/widgets/peer_widget.dart +++ b/flutter/lib/desktop/widgets/peer_widget.dart @@ -100,10 +100,10 @@ class _PeerWidgetState extends State<_PeerWidget> with WindowListener { offstage: super.widget._offstageFunc(peer), child: Obx( () => Container( - width: 225, + width: 220, height: peerCardUiType.value == PeerUiType.grid - ? 150 - : 50, + ? 140 + : 42, child: VisibilityDetector( key: Key('${peer.id}'), onVisibilityChanged: (info) { diff --git a/flutter/lib/desktop/widgets/peercard_widget.dart b/flutter/lib/desktop/widgets/peercard_widget.dart index e8f4d6801..f76336cda 100644 --- a/flutter/lib/desktop/widgets/peercard_widget.dart +++ b/flutter/lib/desktop/widgets/peercard_widget.dart @@ -36,29 +36,31 @@ class _PeerCard extends StatefulWidget { class _PeerCardState extends State<_PeerCard> with AutomaticKeepAliveClientMixin { var _menuPos; + final double _cardRadis = 20; + final double _borderWidth = 2; @override Widget build(BuildContext context) { super.build(context); final peer = super.widget.peer; var deco = Rx(BoxDecoration( - border: Border.all(color: Colors.transparent, width: 1.0), + border: Border.all(color: Colors.transparent, width: _borderWidth), borderRadius: peerCardUiType.value == PeerUiType.grid - ? BorderRadius.circular(20) + ? BorderRadius.circular(_cardRadis) : null)); return MouseRegion( onEnter: (evt) { deco.value = BoxDecoration( - border: Border.all(color: Colors.blue, width: 1.0), + border: Border.all(color: MyTheme.button, width: _borderWidth), borderRadius: peerCardUiType.value == PeerUiType.grid - ? BorderRadius.circular(20) + ? BorderRadius.circular(_cardRadis) : null); }, onExit: (evt) { deco.value = BoxDecoration( - border: Border.all(color: Colors.transparent, width: 1.0), + border: Border.all(color: Colors.transparent, width: _borderWidth), borderRadius: peerCardUiType.value == PeerUiType.grid - ? BorderRadius.circular(20) + ? BorderRadius.circular(_cardRadis) : null); }, child: GestureDetector( @@ -71,25 +73,25 @@ class _PeerCardState extends State<_PeerCard> Widget _buildPeerTile( BuildContext context, Peer peer, Rx deco) { - final greyStyle = TextStyle(fontSize: 12, color: Colors.grey); + final greyStyle = + TextStyle(fontSize: 12, color: MyTheme.color(context).lighterText); + RxBool iconHover = false.obs; return Obx( () => Container( - decoration: deco.value, + foregroundDecoration: deco.value, child: Row( mainAxisSize: MainAxisSize.max, children: [ Container( - height: 50, - width: 50, decoration: BoxDecoration( color: str2color('${peer.id}${peer.platform}', 0x7f), ), alignment: Alignment.center, - child: _getPlatformImage('${peer.platform}').paddingAll(8.0), + child: _getPlatformImage('${peer.platform}', 30).paddingAll(6), ), Expanded( child: Container( - decoration: BoxDecoration(color: Colors.white), + decoration: BoxDecoration(color: MyTheme.color(context).bg), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -98,17 +100,17 @@ class _PeerCardState extends State<_PeerCard> mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ Row(children: [ - Text( - '${peer.id}', - style: TextStyle(fontWeight: FontWeight.w400), - ), Padding( - padding: EdgeInsets.fromLTRB(4, 4, 8, 4), + padding: EdgeInsets.fromLTRB(0, 4, 4, 4), child: CircleAvatar( radius: 5, backgroundColor: peer.online ? Colors.green : Colors.yellow)), + Text( + '${peer.id}', + style: TextStyle(fontWeight: FontWeight.w400), + ), ]), Align( alignment: Alignment.centerLeft, @@ -122,6 +124,7 @@ class _PeerCardState extends State<_PeerCard> : snapshot.data!; return Tooltip( message: name, + waitDuration: Duration(seconds: 1), child: Text( name, style: greyStyle, @@ -145,17 +148,31 @@ class _PeerCardState extends State<_PeerCard> ), ), InkWell( - child: Icon(Icons.more_vert), - onTapDown: (e) { - final x = e.globalPosition.dx; - final y = e.globalPosition.dy; - _menuPos = RelativeRect.fromLTRB(x, y, x, y); - }, - onTap: () { - _showPeerMenu(context, peer.id); - }), + child: CircleAvatar( + radius: 12, + backgroundColor: iconHover.value + ? MyTheme.color(context).grayBg! + : MyTheme.color(context).bg!, + child: Icon( + Icons.more_vert, + size: 18, + color: iconHover.value + ? MyTheme.color(context).text + : MyTheme.color(context).lightText, + ), + ), + onTapDown: (e) { + final x = e.globalPosition.dx; + final y = e.globalPosition.dy; + _menuPos = RelativeRect.fromLTRB(x, y, x, y); + }, + onTap: () { + _showPeerMenu(context, peer.id); + }, + onHover: (value) => iconHover.value = value, + ), ], - ).paddingSymmetric(horizontal: 8.0), + ).paddingSymmetric(horizontal: 4.0), ), ) ], @@ -166,105 +183,121 @@ class _PeerCardState extends State<_PeerCard> Widget _buildPeerCard( BuildContext context, Peer peer, Rx deco) { + RxBool iconHover = false.obs; return Card( - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), + color: Colors.transparent, + elevation: 0, + margin: EdgeInsets.zero, child: Obx( () => Container( - decoration: deco.value, - child: Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Expanded( - child: Container( - decoration: BoxDecoration( + foregroundDecoration: deco.value, + child: ClipRRect( + borderRadius: BorderRadius.circular(_cardRadis - _borderWidth), + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + child: Container( color: str2color('${peer.id}${peer.platform}', 0x7f), - borderRadius: BorderRadius.only( - topLeft: Radius.circular(20), - topRight: Radius.circular(20), - ), - ), - child: Row( - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Container( - padding: const EdgeInsets.all(6), - child: _getPlatformImage('${peer.platform}'), - ), - Row( - children: [ - Expanded( - child: FutureBuilder( - future: bind.mainGetPeerOption( - id: peer.id, key: 'alias'), - builder: (_, snapshot) { - if (snapshot.hasData) { - final name = snapshot.data!.isEmpty - ? '${peer.username}@${peer.hostname}' - : snapshot.data!; - return Tooltip( - message: name, - child: Text( - name, + child: Row( + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + padding: const EdgeInsets.all(6), + child: + _getPlatformImage('${peer.platform}', 60), + ), + Row( + children: [ + Expanded( + child: FutureBuilder( + future: bind.mainGetPeerOption( + id: peer.id, key: 'alias'), + builder: (_, snapshot) { + if (snapshot.hasData) { + final name = snapshot.data!.isEmpty + ? '${peer.username}@${peer.hostname}' + : snapshot.data!; + return Tooltip( + message: name, + waitDuration: Duration(seconds: 1), + child: Text( + name, + style: TextStyle( + color: Colors.white70, + fontSize: 12), + textAlign: TextAlign.center, + overflow: TextOverflow.ellipsis, + ), + ); + } else { + // alias has not arrived + return Center( + child: Text( + '${peer.username}@${peer.hostname}', style: TextStyle( color: Colors.white70, fontSize: 12), textAlign: TextAlign.center, overflow: TextOverflow.ellipsis, - ), - ); - } else { - // alias has not arrived - return Center( - child: Text( - '${peer.username}@${peer.hostname}', - style: TextStyle( - color: Colors.white70, - fontSize: 12), - textAlign: TextAlign.center, - overflow: TextOverflow.ellipsis, - )); - } - }, + )); + } + }, + ), ), - ), - ], - ), - ], - ).paddingAll(4.0), - ), - ], + ], + ), + ], + ).paddingAll(4.0), + ), + ], + ), ), ), - ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row(children: [ - Padding( - padding: EdgeInsets.fromLTRB(0, 4, 8, 4), - child: CircleAvatar( - radius: 5, - backgroundColor: - peer.online ? Colors.green : Colors.yellow)), - Text('${peer.id}') - ]), - InkWell( - child: Icon(Icons.more_vert), - onTapDown: (e) { - final x = e.globalPosition.dx; - final y = e.globalPosition.dy; - _menuPos = RelativeRect.fromLTRB(x, y, x, y); - }, - onTap: () { - _showPeerMenu(context, peer.id); - }), - ], - ).paddingSymmetric(vertical: 8.0, horizontal: 12.0) - ], + Container( + color: MyTheme.color(context).bg, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row(children: [ + Padding( + padding: EdgeInsets.fromLTRB(0, 4, 8, 4), + child: CircleAvatar( + radius: 5, + backgroundColor: peer.online + ? Colors.green + : Colors.yellow)), + Text('${peer.id}') + ]), + InkWell( + child: CircleAvatar( + radius: 12, + backgroundColor: iconHover.value + ? MyTheme.color(context).grayBg! + : MyTheme.color(context).bg!, + child: Icon(Icons.more_vert, + size: 18, + color: iconHover.value + ? MyTheme.color(context).text + : MyTheme.color(context).lightText)), + onTapDown: (e) { + final x = e.globalPosition.dx; + final y = e.globalPosition.dy; + _menuPos = RelativeRect.fromLTRB(x, y, x, y); + }, + onTap: () { + _showPeerMenu(context, peer.id); + }, + onHover: (value) => iconHover.value = value), + ], + ).paddingSymmetric(vertical: 8.0, horizontal: 12.0), + ) + ], + ), ), ), ), @@ -365,12 +398,12 @@ class _PeerCardState extends State<_PeerCard> } /// Get the image for the current [platform]. - Widget _getPlatformImage(String platform) { + Widget _getPlatformImage(String platform, double size) { platform = platform.toLowerCase(); if (platform == 'mac os') platform = 'mac'; else if (platform != 'linux' && platform != 'android') platform = 'win'; - return Image.asset('assets/$platform.png', height: 50); + return Image.asset('assets/$platform.png', height: size, width: size); } void _abEditTag(String id) { diff --git a/flutter/lib/desktop/widgets/tabbar_widget.dart b/flutter/lib/desktop/widgets/tabbar_widget.dart index 3b88deae6..09f1ee4b5 100644 --- a/flutter/lib/desktop/widgets/tabbar_widget.dart +++ b/flutter/lib/desktop/widgets/tabbar_widget.dart @@ -514,8 +514,10 @@ class ActionIcon extends StatelessWidget { RxBool hover = false.obs; return Obx(() => Tooltip( message: translate(message), + waitDuration: Duration(seconds: 1), child: InkWell( - hoverColor: is_close ? Colors.red : theme.hoverColor, + hoverColor: + is_close ? Color.fromARGB(255, 196, 43, 28) : theme.hoverColor, onHover: (value) => hover.value = value, child: Container( height: _kTabBarHeight - 1, diff --git a/flutter/pubspec.yaml b/flutter/pubspec.yaml index da6a3cd3e..06231f8bf 100644 --- a/flutter/pubspec.yaml +++ b/flutter/pubspec.yaml @@ -107,9 +107,14 @@ flutter: - family: GestureIcons fonts: - asset: assets/gestures.ttf - - family: IconFont + - family: Tabbar fonts: - asset: assets/tabbar.ttf + - family: PeerSearchbar + fonts: + - asset: assets/peer_searchbar.ttf + + # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware.