allow hide peer tab

Signed-off-by: 21pages <pages21@163.com>
This commit is contained in:
21pages 2023-09-14 16:30:45 +08:00
parent 348ed268c3
commit 09d380ba8f
3 changed files with 157 additions and 10 deletions

View File

@ -1,3 +1,6 @@
import 'dart:ui' as ui;
import 'package:bot_toast/bot_toast.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hbb/common/widgets/address_book.dart';
import 'package:flutter_hbb/common/widgets/dialog.dart';
@ -6,6 +9,9 @@ import 'package:flutter_hbb/common/widgets/peers_view.dart';
import 'package:flutter_hbb/common/widgets/peer_card.dart';
import 'package:flutter_hbb/consts.dart';
import 'package:flutter_hbb/desktop/widgets/popup_menu.dart';
import 'package:flutter_hbb/desktop/widgets/material_mod_popup_menu.dart'
as mod_menu;
import 'package:flutter_hbb/desktop/widgets/tabbar_widget.dart';
import 'package:flutter_hbb/models/ab_model.dart';
import 'package:flutter_hbb/models/peer_tab_model.dart';
@ -61,6 +67,7 @@ class _PeerTabPageState extends State<PeerTabPage>
({dynamic hint}) => gFFI.groupModel.pull(force: hint == null),
),
];
RelativeRect? mobileTabContextMenuPos;
@override
void initState() {
@ -100,7 +107,9 @@ class _PeerTabPageState extends State<PeerTabPage>
child: selectionWrap(Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(child: _createSwitchBar(context)),
Expanded(
child:
visibleContextMenuListener(_createSwitchBar(context))),
const PeerSearchBar().marginOnly(right: isMobile ? 0 : 13),
_createRefresh(),
_createMultiSelection(),
@ -145,7 +154,7 @@ class _PeerTabPageState extends State<PeerTabPage>
return ListView(
scrollDirection: Axis.horizontal,
physics: NeverScrollableScrollPhysics(),
children: model.indexs.map((t) {
children: model.visibleIndexs.map((t) {
final selected = model.currentTab == t;
final color = selected
? MyTheme.tabbar(context).selectedTextColor
@ -164,8 +173,10 @@ class _PeerTabPageState extends State<PeerTabPage>
decoration:
selected ? decoBorder : (hover.value ? deco : null),
child: Tooltip(
preferBelow: false,
message:
model.tabTooltip(t, gFFI.groupModel.groupName.value),
onTriggered: isMobile ? mobileShowTabVisibilityMenu : null,
child: Icon(model.tabIcon(t), color: color),
).paddingSymmetric(horizontal: 4),
).paddingSymmetric(horizontal: 4),
@ -182,14 +193,15 @@ class _PeerTabPageState extends State<PeerTabPage>
Widget _createPeersView() {
final model = Provider.of<PeerTabModel>(context);
Widget child;
if (model.indexs.isEmpty) {
child = Center(
child: Text(translate('Right click to select tabs')),
);
if (model.visibleIndexs.isEmpty) {
child = visibleContextMenuListener(Row(
children: [Expanded(child: InkWell())],
));
} else {
if (model.indexs.contains(model.currentTab)) {
if (model.visibleIndexs.contains(model.currentTab)) {
child = entries[model.currentTab].widget;
} else {
debugPrint("should not happen! currentTab not in visibleIndexs");
Future.delayed(Duration.zero, () {
model.setCurrentTab(model.indexs[0]);
});
@ -268,6 +280,96 @@ class _PeerTabPageState extends State<PeerTabPage>
);
}
void mobileShowTabVisibilityMenu() {
final model = gFFI.peerTabModel;
final items = List<PopupMenuItem>.empty(growable: true);
for (int i = 0; i < model.tabNames.length; i++) {
items.add(PopupMenuItem(
height: kMinInteractiveDimension * 0.8,
onTap: () => model.setTabVisible(i, !model.isVisible[i]),
child: Row(
children: [
Checkbox(
value: model.isVisible[i],
onChanged: (_) {
model.setTabVisible(i, !model.isVisible[i]);
if (Navigator.canPop(context)) {
Navigator.pop(context);
}
}),
Expanded(
child:
Text(model.tabTooltip(i, gFFI.groupModel.groupName.value))),
],
),
));
}
if (mobileTabContextMenuPos != null) {
showMenu(
context: context, position: mobileTabContextMenuPos!, items: items);
}
}
Widget visibleContextMenuListener(Widget child) {
if (isMobile) {
return GestureDetector(
onLongPressDown: (e) {
final x = e.globalPosition.dx;
final y = e.globalPosition.dy;
mobileTabContextMenuPos = RelativeRect.fromLTRB(x, y, x, y);
},
onLongPressUp: () {
mobileShowTabVisibilityMenu();
},
child: child,
);
} else {
return Listener(
onPointerDown: (e) {
if (e.kind != ui.PointerDeviceKind.mouse) {
return;
}
if (e.buttons == 2) {
showRightMenu(
(CancelFunc cancelFunc) {
return visibleContextMenu(cancelFunc);
},
target: e.position,
);
}
},
child: child);
}
}
Widget visibleContextMenu(CancelFunc cancelFunc) {
final model = Provider.of<PeerTabModel>(context);
final menu = List<MenuEntrySwitch>.empty(growable: true);
for (int i = 0; i < model.tabNames.length; i++) {
menu.add(MenuEntrySwitch(
switchType: SwitchType.scheckbox,
text: model.tabTooltip(i, gFFI.groupModel.groupName.value),
getter: () async {
return model.isVisible[i];
},
setter: (show) async {
model.setTabVisible(i, show);
cancelFunc();
}));
}
return mod_menu.PopupMenu(
items: menu
.map((entry) => entry.build(
context,
const MenuConfig(
commonColor: MyTheme.accent,
height: 20.0,
dividerHeight: 12.0,
)))
.expand((i) => i)
.toList());
}
Widget createMultiSelectionBar() {
final model = Provider.of<PeerTabModel>(context);
return Row(

View File

@ -1,3 +1,4 @@
import 'dart:convert';
import 'dart:math';
import 'package:flutter/material.dart';
@ -36,7 +37,10 @@ class PeerTabModel with ChangeNotifier {
IconFont.addressBook,
Icons.group,
];
final List<bool> _isVisible = List.filled(4, true, growable: false);
List<bool> get isVisible => _isVisible;
List<int> get indexs => List.generate(tabNames.length, (index) => index);
List<int> get visibleIndexs => indexs.where((e) => _isVisible[e]).toList();
List<Peer> _selectedPeers = List.empty(growable: true);
List<Peer> get selectedPeers => _selectedPeers;
bool _multiSelectionMode = false;
@ -49,12 +53,29 @@ class PeerTabModel with ChangeNotifier {
String get lastId => _lastId;
PeerTabModel(this.parent) {
// visible
try {
final option = bind.getLocalFlutterOption(k: 'peer-tab-visible');
if (option.isNotEmpty) {
List<dynamic> decodeList = jsonDecode(option);
if (decodeList.length == _isVisible.length) {
for (int i = 0; i < _isVisible.length; i++) {
if (decodeList[i] is bool) {
_isVisible[i] = decodeList[i];
}
}
}
}
} catch (e) {
debugPrint("failed to get peer tab visible list:$e");
}
// init currentTab
_currentTab =
int.tryParse(bind.getLocalFlutterOption(k: 'peer-tab-index')) ?? 0;
if (_currentTab < 0 || _currentTab >= tabNames.length) {
_currentTab = 0;
}
_trySetCurrentTabToFirstVisible();
}
setCurrentTab(int index) {
@ -158,4 +179,31 @@ class PeerTabModel with ChangeNotifier {
}
}
}
setTabVisible(int index, bool visible) {
if (index >= 0 && index < _isVisible.length) {
if (_isVisible[index] != visible) {
_isVisible[index] = visible;
if (index == _currentTab && !visible) {
_trySetCurrentTabToFirstVisible();
} else if (visible && visibleIndexs.length == 1) {
_currentTab = index;
}
try {
bind.setLocalFlutterOption(
k: 'peer-tab-visible', v: jsonEncode(_isVisible));
} catch (_) {}
notifyListeners();
}
}
}
_trySetCurrentTabToFirstVisible() {
if (!_isVisible[_currentTab]) {
int firstVisible = _isVisible.indexWhere((e) => e);
if (firstVisible >= 0) {
_currentTab = firstVisible;
}
}
}
}

View File

@ -57,7 +57,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("ID Server", "ID serveris"),
("Relay Server", "Releja serveris"),
("API Server", "API serveris"),
("Key", "Atslēga"),
("invalid_http", "jāsākas ar http:// vai https://"),
("Invalid IP", "Nederīga IP"),
("Invalid format", "Nederīgs formāts"),
@ -297,7 +296,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("This file exists, skip or overwrite this file?", "Šis fails pastāv, izlaist vai pārrakstīt šo failu?"),
("Quit", "Iziet"),
("doc_mac_permission", "https://rustdesk.com/docs/en/manual/mac/#enable-permissions"),
("doc_fix_wayland", "https://rustdesk.com/docs/en/manual/linux/#x11-required"),
("Help", "Palīdzība"),
("Failed", "Neizdevās"),
("Succeeded", "Izdevās"),
@ -481,7 +479,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Me", "Es"),
("identical_file_tip", "Šis fails ir identisks sesijas failam."),
("show_monitors_tip", "Rādīt monitorus rīkjoslā"),
("enter_rustdesk_passwd_tip", "Ievadiet RustDesk paroli"),
("View Mode", "Skatīšanas režīms"),
("login_linux_tip", "Jums ir jāpiesakās attālajā Linux kontā, lai iespējotu X darbvirsmas sesiju"),
("verify_rustdesk_password_tip", "Pārbaudīt RustDesk paroli"),