mirror of
https://github.com/rustdesk/rustdesk.git
synced 2025-12-12 11:06:57 +00:00
@@ -1,7 +1,3 @@
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:bot_toast/bot_toast.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hbb/common/widgets/address_book.dart';
|
||||
import 'package:flutter_hbb/common/widgets/my_group.dart';
|
||||
@@ -10,16 +6,13 @@ 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';
|
||||
import 'package:flutter_hbb/desktop/widgets/material_mod_popup_menu.dart'
|
||||
as mod_menu;
|
||||
|
||||
import 'package:flutter_hbb/models/peer_tab_model.dart';
|
||||
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 '../../common.dart';
|
||||
import '../../models/group_model.dart';
|
||||
import '../../models/platform_model.dart';
|
||||
|
||||
class PeerTabPage extends StatefulWidget {
|
||||
@@ -68,7 +61,6 @@ class _PeerTabPageState extends State<PeerTabPage>
|
||||
() => gFFI.groupModel.pull(),
|
||||
),
|
||||
];
|
||||
final _scrollDebounce = Debouncer(delay: Duration(milliseconds: 50));
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -101,11 +93,8 @@ class _PeerTabPageState extends State<PeerTabPage>
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Expanded(
|
||||
child:
|
||||
visibleContextMenuListener(_createSwitchBar(context))),
|
||||
buildScrollJumper(),
|
||||
const PeerSearchBar().marginOnly(right: 13),
|
||||
Expanded(child: _createSwitchBar(context)),
|
||||
const PeerSearchBar().marginOnly(right: isMobile ? 0 : 13),
|
||||
_createRefresh(),
|
||||
Offstage(
|
||||
offstage: !isDesktop,
|
||||
@@ -124,121 +113,58 @@ class _PeerTabPageState extends State<PeerTabPage>
|
||||
}
|
||||
|
||||
Widget _createSwitchBar(BuildContext context) {
|
||||
getListener({required Key key, required Widget child, required int index}) {
|
||||
if (isMobile) {
|
||||
return ReorderableDelayedDragStartListener(
|
||||
key: key, child: child, index: index);
|
||||
} else {
|
||||
return ReorderableDragStartListener(
|
||||
key: key, child: child, index: index);
|
||||
}
|
||||
final model = Provider.of<PeerTabModel>(context);
|
||||
|
||||
getTabChild(int t) {
|
||||
final color = model.currentTab == t
|
||||
? MyTheme.tabbar(context).selectedTextColor
|
||||
: MyTheme.tabbar(context).unSelectedTextColor
|
||||
?..withOpacity(0.5);
|
||||
return Obx(() => Tooltip(
|
||||
message: model.tabTooltip(t, gFFI.groupModel.groupName.value),
|
||||
child: Icon(model.tabIcon(t), color: color),
|
||||
));
|
||||
}
|
||||
|
||||
final model = Provider.of<PeerTabModel>(context);
|
||||
int indexCounter = -1;
|
||||
return ReorderableListView(
|
||||
buildDefaultDragHandles: false,
|
||||
onReorder: (oldIndex, newIndex) {
|
||||
model.onReorder(oldIndex, newIndex);
|
||||
},
|
||||
return ListView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
scrollController: model.sc,
|
||||
children: model.visibleOrderedTabs.map((t) {
|
||||
indexCounter++;
|
||||
return getListener(
|
||||
key: ValueKey(t),
|
||||
index: indexCounter,
|
||||
child: VisibilityDetector(
|
||||
key: ValueKey(t),
|
||||
onVisibilityChanged: (info) {
|
||||
final id = (info.key as ValueKey).value;
|
||||
model.setTabFullyVisible(id, info.visibleFraction > 0.99);
|
||||
},
|
||||
child: Listener(
|
||||
// handle mouse wheel
|
||||
onPointerSignal: (e) {
|
||||
if (e is PointerScrollEvent) {
|
||||
if (!model.sc.canScroll) return;
|
||||
_scrollDebounce.call(() {
|
||||
model.sc.animateTo(model.sc.offset + e.scrollDelta.dy,
|
||||
duration: Duration(milliseconds: 200),
|
||||
curve: Curves.ease);
|
||||
});
|
||||
}
|
||||
},
|
||||
child: InkWell(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
decoration: BoxDecoration(
|
||||
color: model.currentTab == t
|
||||
? Theme.of(context).colorScheme.background
|
||||
: null,
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
child: Align(
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
model.translatedTabname(t),
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
height: 1,
|
||||
fontSize: 14,
|
||||
color: model.currentTab == t
|
||||
? MyTheme.tabbar(context).selectedTextColor
|
||||
: MyTheme.tabbar(context).unSelectedTextColor
|
||||
?..withOpacity(0.5)),
|
||||
),
|
||||
)),
|
||||
onTap: () async {
|
||||
await handleTabSelection(t);
|
||||
await bind.setLocalFlutterConfig(
|
||||
k: 'peer-tab-index', v: t.toString());
|
||||
},
|
||||
children: model.indexs.map((t) {
|
||||
return InkWell(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
decoration: BoxDecoration(
|
||||
color: model.currentTab == t
|
||||
? Theme.of(context).colorScheme.background
|
||||
: null,
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
),
|
||||
),
|
||||
child: Align(
|
||||
alignment: Alignment.center,
|
||||
child: getTabChild(t),
|
||||
)),
|
||||
onTap: () async {
|
||||
await handleTabSelection(t);
|
||||
await bind.setLocalFlutterConfig(
|
||||
k: 'peer-tab-index', v: t.toString());
|
||||
},
|
||||
);
|
||||
}).toList());
|
||||
}
|
||||
|
||||
Widget buildScrollJumper() {
|
||||
final model = Provider.of<PeerTabModel>(context);
|
||||
return Offstage(
|
||||
offstage: !model.showScrollBtn,
|
||||
child: Row(
|
||||
children: [
|
||||
GestureDetector(
|
||||
child: Icon(Icons.arrow_left,
|
||||
size: 22,
|
||||
color: model.leftFullyVisible
|
||||
? Theme.of(context).disabledColor
|
||||
: null),
|
||||
onTap: model.sc.backward),
|
||||
GestureDetector(
|
||||
child: Icon(Icons.arrow_right,
|
||||
size: 22,
|
||||
color: model.rightFullyVisible
|
||||
? Theme.of(context).disabledColor
|
||||
: null),
|
||||
onTap: model.sc.forward)
|
||||
],
|
||||
));
|
||||
}
|
||||
|
||||
Widget _createPeersView() {
|
||||
final model = Provider.of<PeerTabModel>(context);
|
||||
Widget child;
|
||||
if (model.visibleOrderedTabs.isEmpty) {
|
||||
child = visibleContextMenuListener(Center(
|
||||
if (model.indexs.isEmpty) {
|
||||
child = Center(
|
||||
child: Text(translate('Right click to select tabs')),
|
||||
));
|
||||
);
|
||||
} else {
|
||||
if (model.visibleOrderedTabs.contains(model.currentTab)) {
|
||||
if (model.indexs.contains(model.currentTab)) {
|
||||
child = entries[model.currentTab].widget;
|
||||
} else {
|
||||
Future.delayed(Duration.zero, () {
|
||||
model.setCurrentTab(model.visibleOrderedTabs[0]);
|
||||
model.setCurrentTab(model.indexs[0]);
|
||||
});
|
||||
child = entries[0].widget;
|
||||
}
|
||||
@@ -300,57 +226,6 @@ class _PeerTabPageState extends State<PeerTabPage>
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget visibleContextMenuListener(Widget child) {
|
||||
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 List<MenuEntryBase> menu = List.empty(growable: true);
|
||||
final List<int> menuIndex = List.empty(growable: true);
|
||||
var list = model.orderedNotFilteredTabs();
|
||||
for (int i = 0; i < list.length; i++) {
|
||||
int tabIndex = list[i];
|
||||
int bitMask = 1 << tabIndex;
|
||||
menuIndex.add(tabIndex);
|
||||
menu.add(MenuEntrySwitch(
|
||||
switchType: SwitchType.scheckbox,
|
||||
text: model.translatedTabname(tabIndex),
|
||||
getter: () async {
|
||||
return model.tabHiddenFlag & bitMask == 0;
|
||||
},
|
||||
setter: (show) async {
|
||||
model.onHideShow(tabIndex, 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());
|
||||
}
|
||||
}
|
||||
|
||||
class PeerSearchBar extends StatefulWidget {
|
||||
|
||||
Reference in New Issue
Block a user