From f5cf291f550c3102f4c2c9a02211461e3062e49e Mon Sep 17 00:00:00 2001 From: 21pages Date: Fri, 4 Aug 2023 13:11:24 +0800 Subject: [PATCH] left shift key for peer card select Signed-off-by: 21pages --- flutter/lib/common/widgets/peer_card.dart | 4 +- flutter/lib/main.dart | 20 +++++++++ flutter/lib/models/peer_tab_model.dart | 52 +++++++++++++++++++---- 3 files changed, 66 insertions(+), 10 deletions(-) diff --git a/flutter/lib/common/widgets/peer_card.dart b/flutter/lib/common/widgets/peer_card.dart index a69b302f5..44178bd5d 100644 --- a/flutter/lib/common/widgets/peer_card.dart +++ b/flutter/lib/common/widgets/peer_card.dart @@ -68,7 +68,7 @@ class _PeerCardState extends State<_PeerCard> child: GestureDetector( onTap: () { if (peerTabModel.multiSelectionMode) { - peerTabModel.onPeerCardTap(peer); + peerTabModel.togglePeerSelect(peer); } else { if (!isWebDesktop) connect(context, peer.id); } @@ -167,7 +167,7 @@ class _PeerCardState extends State<_PeerCard> peerTabModel.togglePeerSelect(peer); }, onTap: peerTabModel.multiSelectionMode - ? () => peerTabModel.onPeerCardTap(peer) + ? () => peerTabModel.togglePeerSelect(peer) : null, child: Obx(() => peerCardUiType.value == PeerUiType.grid ? _buildPeerCard(context, peer, deco) diff --git a/flutter/lib/main.dart b/flutter/lib/main.dart index 59ff18615..4578c2f21 100644 --- a/flutter/lib/main.dart +++ b/flutter/lib/main.dart @@ -5,6 +5,7 @@ import 'dart:io'; import 'package:bot_toast/bot_toast.dart'; import 'package:desktop_multi_window/desktop_multi_window.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_hbb/desktop/pages/desktop_tab_page.dart'; import 'package:flutter_hbb/desktop/pages/install_page.dart'; import 'package:flutter_hbb/desktop/pages/server_page.dart'; @@ -417,6 +418,9 @@ class _AppState extends State { : (context, child) { child = _keepScaleBuilder(context, child); child = botToastBuilder(context, child); + if (desktopType == DesktopType.main) { + child = keyListenerBuilder(context, child); + } return child; }, ), @@ -453,3 +457,19 @@ _registerEventHandler() { }); } } + +Widget keyListenerBuilder(BuildContext context, Widget? child) { + return RawKeyboardListener( + focusNode: FocusNode(), + child: child ?? Container(), + onKey: (RawKeyEvent event) { + if (event.logicalKey == LogicalKeyboardKey.shiftLeft) { + if (event is RawKeyDownEvent) { + gFFI.peerTabModel.isShiftDown = true; + } else if (event is RawKeyUpEvent) { + gFFI.peerTabModel.isShiftDown = false; + } + } + }, + ); +} diff --git a/flutter/lib/models/peer_tab_model.dart b/flutter/lib/models/peer_tab_model.dart index 31d1855e8..024158ccc 100644 --- a/flutter/lib/models/peer_tab_model.dart +++ b/flutter/lib/models/peer_tab_model.dart @@ -1,3 +1,5 @@ +import 'dart:math'; + import 'package:flutter/material.dart'; import 'package:flutter_hbb/models/peer_model.dart'; import 'package:flutter_hbb/models/platform_model.dart'; @@ -40,6 +42,8 @@ class PeerTabModel with ChangeNotifier { bool get multiSelectionMode => _selectedPeers.isNotEmpty; List _currentTabCachedPeers = List.empty(growable: true); List get currentTabCachedPeers => _currentTabCachedPeers; + bool isShiftDown = false; + String? _shiftAnchorId; PeerTabModel(this.parent) { // init currentTab @@ -82,21 +86,53 @@ class PeerTabModel with ChangeNotifier { } togglePeerSelect(Peer peer) { - if (_selectedPeers.firstWhereOrNull((p) => p.id == peer.id) != null) { - _selectedPeers.removeWhere((p) => p.id == peer.id); + final cached = _currentTabCachedPeers.map((e) => e.id).toList(); + int thisIndex = cached.indexOf(peer.id); + int closestIndex = -1; + String? closestId; + int smallestDiff = -1; + for (var i = 0; i < cached.length; i++) { + if (isPeerSelected(cached[i])) { + int diff = (i - thisIndex).abs(); + if (smallestDiff == -1 || diff < smallestDiff) { + closestIndex = i; + closestId = cached[i]; + smallestDiff = diff; + } + } + } + if (isShiftDown && + thisIndex >= 0 && + closestIndex >= 0 && + closestId != null) { + int shiftAnchorIndex = cached.indexOf(_shiftAnchorId ?? ''); + if (shiftAnchorIndex < 0) { + // use closest as shift anchor, rather than focused which we don't have + shiftAnchorIndex = closestIndex; + _shiftAnchorId = closestId; + } + int start = min(shiftAnchorIndex, thisIndex); + int end = max(shiftAnchorIndex, thisIndex); + _selectedPeers.clear(); + for (var i = start; i <= end; i++) { + if (!isPeerSelected(cached[i])) { + _selectedPeers.add(_currentTabCachedPeers[i]); + } + } } else { - _selectedPeers.add(peer); + if (isPeerSelected(peer.id)) { + _selectedPeers.removeWhere((p) => p.id == peer.id); + } else { + _selectedPeers.add(peer); + } + _shiftAnchorId = null; } notifyListeners(); } - onPeerCardTap(Peer peer) { - if (!multiSelectionMode) return; - togglePeerSelect(peer); - } - closeSelection() { _selectedPeers.clear(); + _shiftAnchorId = null; notifyListeners(); }