From 0bda66dd7fa22349e53334b0e634a940b7a1068e Mon Sep 17 00:00:00 2001 From: 21pages Date: Wed, 21 Jun 2023 11:51:35 +0800 Subject: [PATCH] peer ab/group tab refresh, animated refresh icon Signed-off-by: 21pages --- .../widgets/animated_rotation_widget.dart | 30 +++++++++++++ flutter/lib/common/widgets/my_group.dart | 2 +- flutter/lib/common/widgets/peer_tab_page.dart | 43 ++++++++++++++----- .../lib/desktop/pages/desktop_home_page.dart | 30 ++++++------- flutter/lib/models/group_model.dart | 3 +- 5 files changed, 81 insertions(+), 27 deletions(-) create mode 100644 flutter/lib/common/widgets/animated_rotation_widget.dart diff --git a/flutter/lib/common/widgets/animated_rotation_widget.dart b/flutter/lib/common/widgets/animated_rotation_widget.dart new file mode 100644 index 000000000..525508e44 --- /dev/null +++ b/flutter/lib/common/widgets/animated_rotation_widget.dart @@ -0,0 +1,30 @@ +import 'package:flutter/material.dart'; + +class AnimatedRotationWidget extends StatefulWidget { + final VoidCallback onPressed; + final ValueChanged? onHover; + final Widget child; + const AnimatedRotationWidget( + {super.key, required this.onPressed, required this.child, this.onHover}); + + @override + State createState() => AnimatedRotationWidgetState(); +} + +class AnimatedRotationWidgetState extends State { + double turns = 0.0; + + @override + Widget build(BuildContext context) { + return AnimatedRotation( + turns: turns, + duration: const Duration(milliseconds: 200), + child: InkWell( + onTap: () { + setState(() => turns += 1.0); + widget.onPressed(); + }, + onHover: widget.onHover, + child: widget.child)); + } +} diff --git a/flutter/lib/common/widgets/my_group.dart b/flutter/lib/common/widgets/my_group.dart index cf7c4ae45..cda640b1f 100644 --- a/flutter/lib/common/widgets/my_group.dart +++ b/flutter/lib/common/widgets/my_group.dart @@ -37,7 +37,7 @@ class _MyGroupState extends State { }); Future buildBody(BuildContext context) async { - gFFI.groupModel.pullUserPeers(); + gFFI.groupModel.pull(); return Obx(() { if (gFFI.groupModel.groupLoading.value || gFFI.groupModel.peerLoading.value) { diff --git a/flutter/lib/common/widgets/peer_tab_page.dart b/flutter/lib/common/widgets/peer_tab_page.dart index 0361ba511..f667ba8cd 100644 --- a/flutter/lib/common/widgets/peer_tab_page.dart +++ b/flutter/lib/common/widgets/peer_tab_page.dart @@ -1,4 +1,3 @@ -import 'dart:math'; import 'dart:ui' as ui; import 'package:bot_toast/bot_toast.dart'; @@ -8,6 +7,7 @@ import 'package:flutter_hbb/common/widgets/address_book.dart'; import 'package:flutter_hbb/common/widgets/my_group.dart'; import 'package:flutter_hbb/common/widgets/peers_view.dart'; import 'package:flutter_hbb/common/widgets/peer_card.dart'; +import 'package:flutter_hbb/common/widgets/animated_rotation_widget.dart'; import 'package:flutter_hbb/consts.dart'; import 'package:flutter_hbb/desktop/widgets/popup_menu.dart'; import 'package:flutter_hbb/desktop/widgets/tabbar_widget.dart'; @@ -18,7 +18,6 @@ import 'package:get/get.dart'; import 'package:get/get_rx/src/rx_workers/utils/debouncer.dart'; import 'package:provider/provider.dart'; import 'package:visibility_detector/visibility_detector.dart'; -import 'package:dropdown_button2/dropdown_button2.dart'; import '../../common.dart'; import '../../models/platform_model.dart'; @@ -63,12 +62,13 @@ class _PeerTabPageState extends State AddressBook( menuPadding: _menuPadding(), ), - () => {}), + () => gFFI.abModel.pullAb()), _TabEntry( - MyGroup( - menuPadding: _menuPadding(), - ), - () => {}), + MyGroup( + menuPadding: _menuPadding(), + ), + () => gFFI.groupModel.pull(), + ), ]; final _scrollDebounce = Debouncer(delay: Duration(milliseconds: 50)); @@ -109,11 +109,11 @@ class _PeerTabPageState extends State child: visibleContextMenuListener(_createSwitchBar(context))), buildScrollJumper(), - const PeerSearchBar(), + const PeerSearchBar().marginOnly(right: 13), + _createRefresh(), Offstage( offstage: !isDesktop, - child: _createPeerViewTypeSwitch(context) - .marginOnly(left: 13)), + child: _createPeerViewTypeSwitch(context)), Offstage( offstage: _hideSort, child: PeerSortDropdown().marginOnly(left: 8), @@ -241,6 +241,29 @@ class _PeerTabPageState extends State child: child.marginSymmetric(vertical: isDesktop ? 12.0 : 6.0)); } + Widget _createRefresh() { + final textColor = Theme.of(context).textTheme.titleLarge?.color; + return Offstage( + offstage: gFFI.peerTabModel.currentTab < 3, // local tab can't see effect + child: Container( + padding: EdgeInsets.all(4.0), + child: AnimatedRotationWidget( + onPressed: () { + if (gFFI.peerTabModel.currentTab < entries.length) { + entries[gFFI.peerTabModel.currentTab].load(); + } + }, + child: RotatedBox( + quarterTurns: 2, + child: Icon( + Icons.refresh, + size: 18, + color: textColor, + ))), + ), + ); + } + Widget _createPeerViewTypeSwitch(BuildContext context) { final textColor = Theme.of(context).textTheme.titleLarge?.color; final deco = BoxDecoration( diff --git a/flutter/lib/desktop/pages/desktop_home_page.dart b/flutter/lib/desktop/pages/desktop_home_page.dart index 9c1b5827a..e074f7598 100644 --- a/flutter/lib/desktop/pages/desktop_home_page.dart +++ b/flutter/lib/desktop/pages/desktop_home_page.dart @@ -6,6 +6,7 @@ import 'package:auto_size_text/auto_size_text.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_hbb/common.dart'; +import 'package:flutter_hbb/common/widgets/animated_rotation_widget.dart'; import 'package:flutter_hbb/common/widgets/custom_password.dart'; import 'package:flutter_hbb/consts.dart'; import 'package:flutter_hbb/desktop/pages/connection_page.dart'; @@ -247,19 +248,19 @@ class _DesktopHomePageState extends State ), ), ), - InkWell( - child: Obx( - () => Icon( - Icons.refresh, - color: refreshHover.value - ? textColor - : Color(0xFFDDDDDD), - size: 22, - ).marginOnly(right: 8, top: 4), - ), - onTap: () => bind.mainUpdateTemporaryPassword(), + AnimatedRotationWidget( + onPressed: () => bind.mainUpdateTemporaryPassword(), + child: Obx(() => RotatedBox( + quarterTurns: 2, + child: Icon( + Icons.refresh, + color: refreshHover.value + ? textColor + : Color(0xFFDDDDDD), + size: 22, + ))), onHover: (value) => refreshHover.value = value, - ), + ).marginOnly(right: 8, top: 4), InkWell( child: Obx( () => Icon( @@ -574,7 +575,7 @@ class _DesktopHomePageState extends State _updateTimer?.cancel(); super.dispose(); } - + Widget buildPluginEntry() { final entries = PluginUiManager.instance.entries.entries; return Offstage( @@ -582,8 +583,7 @@ class _DesktopHomePageState extends State child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - ... - entries.map((entry) { + ...entries.map((entry) { return entry.value; }) ], diff --git a/flutter/lib/models/group_model.dart b/flutter/lib/models/group_model.dart index bcd0ab9f1..411703237 100644 --- a/flutter/lib/models/group_model.dart +++ b/flutter/lib/models/group_model.dart @@ -103,6 +103,7 @@ class GroupModel { } finally { groupLoading.value = false; gFFI.peerTabModel.check_dynamic_tabs(); + _pullUserPeers(); } } @@ -134,7 +135,7 @@ class GroupModel { return false; } - Future pullUserPeers() async { + Future _pullUserPeers() async { peersShow.clear(); peerLoading.value = true; peerLoadError.value = "";