mirror of
https://github.com/weyne85/rustdesk.git
synced 2025-10-29 17:00:05 +00:00
Merge remote-tracking branch 'rd/master' into feat/x11/clipboard-file/init
Signed-off-by: ClSlaid <cailue@bupt.edu.cn>
This commit is contained in:
@@ -1,3 +1,6 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:dynamic_layouts/dynamic_layouts.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hbb/common/formatter/id_formatter.dart';
|
||||
import 'package:flutter_hbb/common/widgets/peer_card.dart';
|
||||
@@ -156,20 +159,31 @@ class _AddressBookState extends State<AddressBook> {
|
||||
} else {
|
||||
tags = gFFI.abModel.tags;
|
||||
}
|
||||
return Wrap(
|
||||
children: tags
|
||||
.map((e) => AddressBookTag(
|
||||
name: e,
|
||||
tags: gFFI.abModel.selectedTags,
|
||||
onTap: () {
|
||||
if (gFFI.abModel.selectedTags.contains(e)) {
|
||||
gFFI.abModel.selectedTags.remove(e);
|
||||
} else {
|
||||
gFFI.abModel.selectedTags.add(e);
|
||||
}
|
||||
}))
|
||||
.toList(),
|
||||
);
|
||||
tagBuilder(String e) {
|
||||
return AddressBookTag(
|
||||
name: e,
|
||||
tags: gFFI.abModel.selectedTags,
|
||||
onTap: () {
|
||||
if (gFFI.abModel.selectedTags.contains(e)) {
|
||||
gFFI.abModel.selectedTags.remove(e);
|
||||
} else {
|
||||
gFFI.abModel.selectedTags.add(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
final gridView = DynamicGridView.builder(
|
||||
shrinkWrap: isMobile,
|
||||
gridDelegate: SliverGridDelegateWithWrapping(),
|
||||
itemCount: tags.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
final e = tags[index];
|
||||
return tagBuilder(e);
|
||||
});
|
||||
final maxHeight = max(MediaQuery.of(context).size.height / 6, 100.0);
|
||||
return isDesktop
|
||||
? gridView
|
||||
: LimitedBox(maxHeight: maxHeight, child: gridView);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -711,6 +711,13 @@ void showWaitUacDialog(
|
||||
(setState, close, context) => CustomAlertDialog(
|
||||
title: null,
|
||||
content: msgboxContent(type, 'Wait', 'wait_accept_uac_tip'),
|
||||
actions: [
|
||||
dialogButton(
|
||||
'OK',
|
||||
icon: Icon(Icons.done_rounded),
|
||||
onPressed: close,
|
||||
),
|
||||
],
|
||||
));
|
||||
}
|
||||
|
||||
@@ -931,7 +938,7 @@ void showElevationError(SessionID sessionId, String type, String title,
|
||||
dialogButton('Cancel', onPressed: () {
|
||||
close();
|
||||
}, isOutline: true),
|
||||
dialogButton('Retry', onPressed: submit),
|
||||
if (text != 'No permission') dialogButton('Retry', onPressed: submit),
|
||||
],
|
||||
onSubmit: submit,
|
||||
onCancel: close,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hbb/common/hbbs/hbbs.dart';
|
||||
import 'package:flutter_hbb/common/widgets/login.dart';
|
||||
@@ -120,6 +122,7 @@ class _MyGroupState extends State<MyGroup> {
|
||||
}
|
||||
|
||||
Widget _buildLeftHeader() {
|
||||
final fontSize = 14.0;
|
||||
return Row(
|
||||
children: [
|
||||
Expanded(
|
||||
@@ -128,16 +131,16 @@ class _MyGroupState extends State<MyGroup> {
|
||||
onChanged: (value) {
|
||||
searchUserText.value = value;
|
||||
},
|
||||
textAlignVertical: TextAlignVertical.center,
|
||||
style: TextStyle(fontSize: fontSize),
|
||||
decoration: InputDecoration(
|
||||
filled: false,
|
||||
prefixIcon: Icon(
|
||||
Icons.search_rounded,
|
||||
color: Theme.of(context).hintColor,
|
||||
),
|
||||
contentPadding: const EdgeInsets.symmetric(vertical: 10),
|
||||
).paddingOnly(top: 2),
|
||||
hintText: translate("Search"),
|
||||
hintStyle:
|
||||
TextStyle(fontSize: 14, color: Theme.of(context).hintColor),
|
||||
hintStyle: TextStyle(fontSize: fontSize),
|
||||
border: InputBorder.none,
|
||||
isDense: true,
|
||||
),
|
||||
@@ -148,16 +151,22 @@ class _MyGroupState extends State<MyGroup> {
|
||||
|
||||
Widget _buildUserContacts() {
|
||||
return Obx(() {
|
||||
return Column(
|
||||
children: gFFI.groupModel.users
|
||||
.where((p0) {
|
||||
if (searchUserText.isNotEmpty) {
|
||||
return p0.name.contains(searchUserText.value);
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.map((e) => _buildUserItem(e))
|
||||
.toList());
|
||||
final items = gFFI.groupModel.users.where((p0) {
|
||||
if (searchUserText.isNotEmpty) {
|
||||
return p0.name
|
||||
.toLowerCase()
|
||||
.contains(searchUserText.value.toLowerCase());
|
||||
}
|
||||
return true;
|
||||
}).toList();
|
||||
final listView = ListView.builder(
|
||||
shrinkWrap: isMobile,
|
||||
itemCount: items.length,
|
||||
itemBuilder: (context, index) => _buildUserItem(items[index]));
|
||||
var maxHeight = max(MediaQuery.of(context).size.height / 6, 100.0);
|
||||
return isDesktop
|
||||
? listView
|
||||
: LimitedBox(maxHeight: maxHeight, child: listView);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -173,6 +182,7 @@ class _MyGroupState extends State<MyGroup> {
|
||||
() {
|
||||
bool selected = selectedUser.value == username;
|
||||
final isMe = username == gFFI.userModel.userName.value;
|
||||
final colorMe = MyTheme.color(context).me!;
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: selected ? MyTheme.color(context).highlight : null,
|
||||
@@ -184,9 +194,42 @@ class _MyGroupState extends State<MyGroup> {
|
||||
child: Container(
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(Icons.person_rounded, color: Colors.grey, size: 16)
|
||||
.marginOnly(right: 4),
|
||||
Expanded(child: Text(isMe ? translate('Me') : username)),
|
||||
Container(
|
||||
width: 20,
|
||||
height: 20,
|
||||
decoration: BoxDecoration(
|
||||
color: str2color(username, 0xAF),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Align(
|
||||
alignment: Alignment.center,
|
||||
child: Center(
|
||||
child: Text(
|
||||
username.characters.first.toUpperCase(),
|
||||
style: TextStyle(color: Colors.white),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
),
|
||||
).marginOnly(right: 4),
|
||||
if (isMe) Flexible(child: Text(username)),
|
||||
if (isMe)
|
||||
Flexible(
|
||||
child: Container(
|
||||
margin: EdgeInsets.only(left: 5),
|
||||
padding: EdgeInsets.symmetric(horizontal: 3, vertical: 1),
|
||||
decoration: BoxDecoration(
|
||||
color: colorMe.withAlpha(20),
|
||||
borderRadius: BorderRadius.all(Radius.circular(2)),
|
||||
border: Border.all(color: colorMe.withAlpha(100))),
|
||||
child: Text(
|
||||
translate('Me'),
|
||||
style: TextStyle(
|
||||
color: colorMe.withAlpha(200), fontSize: 12),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (!isMe) Expanded(child: Text(username)),
|
||||
],
|
||||
).paddingSymmetric(vertical: 4),
|
||||
),
|
||||
|
||||
@@ -863,12 +863,12 @@ class RecentPeerCard extends BasePeerCard {
|
||||
|
||||
final List favs = (await bind.mainGetFav()).toList();
|
||||
|
||||
if (isDesktop && peer.platform != 'Android') {
|
||||
if (isDesktop && peer.platform != kPeerPlatformAndroid) {
|
||||
menuItems.add(_tcpTunnelingAction(context, peer.id));
|
||||
}
|
||||
// menuItems.add(await _openNewConnInOptAction(peer.id));
|
||||
menuItems.add(await _forceAlwaysRelayAction(peer.id));
|
||||
if (peer.platform == 'Windows') {
|
||||
if (Platform.isWindows && peer.platform == kPeerPlatformWindows) {
|
||||
menuItems.add(_rdpAction(context, peer.id));
|
||||
}
|
||||
if (Platform.isWindows) {
|
||||
@@ -917,12 +917,12 @@ class FavoritePeerCard extends BasePeerCard {
|
||||
_connectAction(context, peer),
|
||||
_transferFileAction(context, peer.id),
|
||||
];
|
||||
if (isDesktop && peer.platform != 'Android') {
|
||||
if (isDesktop && peer.platform != kPeerPlatformAndroid) {
|
||||
menuItems.add(_tcpTunnelingAction(context, peer.id));
|
||||
}
|
||||
// menuItems.add(await _openNewConnInOptAction(peer.id));
|
||||
menuItems.add(await _forceAlwaysRelayAction(peer.id));
|
||||
if (peer.platform == 'Windows') {
|
||||
if (Platform.isWindows && peer.platform == kPeerPlatformWindows) {
|
||||
menuItems.add(_rdpAction(context, peer.id));
|
||||
}
|
||||
if (Platform.isWindows) {
|
||||
@@ -971,12 +971,12 @@ class DiscoveredPeerCard extends BasePeerCard {
|
||||
|
||||
final List favs = (await bind.mainGetFav()).toList();
|
||||
|
||||
if (isDesktop && peer.platform != 'Android') {
|
||||
if (isDesktop && peer.platform != kPeerPlatformAndroid) {
|
||||
menuItems.add(_tcpTunnelingAction(context, peer.id));
|
||||
}
|
||||
// menuItems.add(await _openNewConnInOptAction(peer.id));
|
||||
menuItems.add(await _forceAlwaysRelayAction(peer.id));
|
||||
if (peer.platform == 'Windows') {
|
||||
if (Platform.isWindows && peer.platform == kPeerPlatformWindows) {
|
||||
menuItems.add(_rdpAction(context, peer.id));
|
||||
}
|
||||
menuItems.add(_wolAction(peer.id));
|
||||
@@ -1021,12 +1021,12 @@ class AddressBookPeerCard extends BasePeerCard {
|
||||
_connectAction(context, peer),
|
||||
_transferFileAction(context, peer.id),
|
||||
];
|
||||
if (isDesktop && peer.platform != 'Android') {
|
||||
if (isDesktop && peer.platform != kPeerPlatformAndroid) {
|
||||
menuItems.add(_tcpTunnelingAction(context, peer.id));
|
||||
}
|
||||
// menuItems.add(await _openNewConnInOptAction(peer.id));
|
||||
menuItems.add(await _forceAlwaysRelayAction(peer.id));
|
||||
if (peer.platform == 'Windows') {
|
||||
if (Platform.isWindows && peer.platform == kPeerPlatformWindows) {
|
||||
menuItems.add(_rdpAction(context, peer.id));
|
||||
}
|
||||
if (Platform.isWindows) {
|
||||
@@ -1089,18 +1089,18 @@ class MyGroupPeerCard extends BasePeerCard {
|
||||
_connectAction(context, peer),
|
||||
_transferFileAction(context, peer.id),
|
||||
];
|
||||
if (isDesktop && peer.platform != 'Android') {
|
||||
if (isDesktop && peer.platform != kPeerPlatformAndroid) {
|
||||
menuItems.add(_tcpTunnelingAction(context, peer.id));
|
||||
}
|
||||
// menuItems.add(await _openNewConnInOptAction(peer.id));
|
||||
// menuItems.add(await _forceAlwaysRelayAction(peer.id));
|
||||
if (peer.platform == 'Windows') {
|
||||
if (Platform.isWindows && peer.platform == kPeerPlatformWindows) {
|
||||
menuItems.add(_rdpAction(context, peer.id));
|
||||
}
|
||||
if (Platform.isWindows) {
|
||||
menuItems.add(_createShortCutAction(peer.id));
|
||||
}
|
||||
menuItems.add(MenuEntryDivider());
|
||||
// menuItems.add(MenuEntryDivider());
|
||||
// menuItems.add(_renameAction(peer.id));
|
||||
// if (await bind.mainPeerHasPassword(id: peer.id)) {
|
||||
// menuItems.add(_unrememberPasswordAction(peer.id));
|
||||
|
||||
@@ -15,8 +15,10 @@ 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';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:pull_down_button/pull_down_button.dart';
|
||||
|
||||
import '../../common.dart';
|
||||
import '../../models/platform_model.dart';
|
||||
@@ -110,43 +112,14 @@ class _PeerTabPageState extends State<PeerTabPage>
|
||||
Expanded(
|
||||
child:
|
||||
visibleContextMenuListener(_createSwitchBar(context))),
|
||||
const PeerSearchBar().marginOnly(right: isMobile ? 0 : 13),
|
||||
_createRefresh(
|
||||
index: PeerTabIndex.ab, loading: gFFI.abModel.abLoading),
|
||||
_createRefresh(
|
||||
index: PeerTabIndex.group,
|
||||
loading: gFFI.groupModel.groupLoading),
|
||||
_createMultiSelection(),
|
||||
Offstage(
|
||||
offstage: !isDesktop,
|
||||
child: _createPeerViewTypeSwitch(context)),
|
||||
Offstage(
|
||||
offstage: gFFI.peerTabModel.currentTab == 0,
|
||||
child: PeerSortDropdown(),
|
||||
),
|
||||
Offstage(
|
||||
offstage: gFFI.peerTabModel.currentTab != 3,
|
||||
child: _hoverAction(
|
||||
context: context,
|
||||
hoverableWhenfalse: hideAbTagsPanel,
|
||||
child: Tooltip(
|
||||
message: translate('Toggle Tags'),
|
||||
child: Icon(
|
||||
Icons.tag_rounded,
|
||||
size: 18,
|
||||
)),
|
||||
onTap: () async {
|
||||
await bind.mainSetLocalOption(
|
||||
key: "hideAbTagsPanel",
|
||||
value: hideAbTagsPanel.value ? "" : "Y");
|
||||
hideAbTagsPanel.value = !hideAbTagsPanel.value;
|
||||
},
|
||||
),
|
||||
),
|
||||
if (isMobile)
|
||||
..._mobileRightActions(context)
|
||||
else
|
||||
..._desktopRightActions(context)
|
||||
],
|
||||
)),
|
||||
),
|
||||
),
|
||||
).paddingOnly(right: isDesktop ? 12 : 0),
|
||||
_createPeersView(),
|
||||
],
|
||||
);
|
||||
@@ -270,17 +243,20 @@ class _PeerTabPageState extends State<PeerTabPage>
|
||||
Widget _createMultiSelection() {
|
||||
final textColor = Theme.of(context).textTheme.titleLarge?.color;
|
||||
final model = Provider.of<PeerTabModel>(context);
|
||||
if (model.currentTabCachedPeers.isEmpty) return Offstage();
|
||||
return _hoverAction(
|
||||
context: context,
|
||||
onTap: () {
|
||||
model.setMultiSelectionMode(true);
|
||||
if (isMobile && Navigator.canPop(context)) {
|
||||
Navigator.pop(context);
|
||||
}
|
||||
},
|
||||
child: Tooltip(
|
||||
message: translate('Select'),
|
||||
child: Icon(
|
||||
IconFont.checkbox,
|
||||
size: 18,
|
||||
child: SvgPicture.asset(
|
||||
"assets/checkbox-outline.svg",
|
||||
width: 18,
|
||||
height: 18,
|
||||
color: textColor,
|
||||
)),
|
||||
);
|
||||
@@ -564,6 +540,130 @@ class _PeerTabPageState extends State<PeerTabPage>
|
||||
Tooltip(message: translate('Close'), child: Icon(Icons.clear)))
|
||||
.marginOnly(left: 6);
|
||||
}
|
||||
|
||||
Widget _toggleTags() {
|
||||
return _hoverAction(
|
||||
context: context,
|
||||
hoverableWhenfalse: hideAbTagsPanel,
|
||||
child: Tooltip(
|
||||
message: translate('Toggle Tags'),
|
||||
child: Icon(
|
||||
Icons.tag_rounded,
|
||||
size: 18,
|
||||
)),
|
||||
onTap: () async {
|
||||
await bind.mainSetLocalOption(
|
||||
key: "hideAbTagsPanel", value: hideAbTagsPanel.value ? "" : "Y");
|
||||
hideAbTagsPanel.value = !hideAbTagsPanel.value;
|
||||
});
|
||||
}
|
||||
|
||||
List<Widget> _desktopRightActions(BuildContext context) {
|
||||
final model = Provider.of<PeerTabModel>(context);
|
||||
return [
|
||||
const PeerSearchBar().marginOnly(right: isMobile ? 0 : 13),
|
||||
_createRefresh(index: PeerTabIndex.ab, loading: gFFI.abModel.abLoading),
|
||||
_createRefresh(
|
||||
index: PeerTabIndex.group, loading: gFFI.groupModel.groupLoading),
|
||||
Offstage(
|
||||
offstage: model.currentTabCachedPeers.isEmpty,
|
||||
child: _createMultiSelection(),
|
||||
),
|
||||
_createPeerViewTypeSwitch(context),
|
||||
Offstage(
|
||||
offstage: model.currentTab == PeerTabIndex.recent.index,
|
||||
child: PeerSortDropdown(),
|
||||
),
|
||||
Offstage(
|
||||
offstage: model.currentTab != PeerTabIndex.ab.index,
|
||||
child: _toggleTags(),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
List<Widget> _mobileRightActions(BuildContext context) {
|
||||
final model = Provider.of<PeerTabModel>(context);
|
||||
final screenWidth = MediaQuery.of(context).size.width;
|
||||
final leftIconSize = Theme.of(context).iconTheme.size ?? 24;
|
||||
final leftActionsSize =
|
||||
(leftIconSize + (4 + 4) * 2) * model.visibleIndexs.length;
|
||||
final availableWidth = screenWidth - 10 * 2 - leftActionsSize - 2 * 2;
|
||||
final searchWidth = 120;
|
||||
final otherActionWidth = 18 + 10;
|
||||
|
||||
dropDown(List<Widget> menus) {
|
||||
final padding = 6.0;
|
||||
final textColor = Theme.of(context).textTheme.titleLarge?.color;
|
||||
return PullDownButton(
|
||||
buttonBuilder:
|
||||
(BuildContext context, Future<void> Function() showMenu) {
|
||||
return _hoverAction(
|
||||
context: context,
|
||||
child: Tooltip(
|
||||
message: translate('More'),
|
||||
child: SvgPicture.asset(
|
||||
"assets/chevron_up_chevron_down.svg",
|
||||
width: 18,
|
||||
height: 18,
|
||||
color: textColor,
|
||||
)),
|
||||
onTap: showMenu,
|
||||
);
|
||||
},
|
||||
routeTheme: PullDownMenuRouteTheme(
|
||||
width: menus.length * (otherActionWidth + padding * 2) * 1.0),
|
||||
itemBuilder: (context) => [
|
||||
PullDownMenuEntryImpl(
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: menus
|
||||
.map((e) =>
|
||||
Material(child: e.paddingSymmetric(horizontal: padding)))
|
||||
.toList(),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
// Always show search, refresh
|
||||
List<Widget> actions = [
|
||||
const PeerSearchBar(),
|
||||
if (model.currentTab == PeerTabIndex.ab.index)
|
||||
_createRefresh(index: PeerTabIndex.ab, loading: gFFI.abModel.abLoading),
|
||||
if (model.currentTab == PeerTabIndex.group.index)
|
||||
_createRefresh(
|
||||
index: PeerTabIndex.group, loading: gFFI.groupModel.groupLoading),
|
||||
];
|
||||
final List<Widget> dynamicActions = [
|
||||
if (model.currentTabCachedPeers.isNotEmpty) _createMultiSelection(),
|
||||
if (model.currentTab != PeerTabIndex.recent.index) PeerSortDropdown(),
|
||||
if (model.currentTab == PeerTabIndex.ab.index) _toggleTags()
|
||||
];
|
||||
final rightWidth = availableWidth -
|
||||
searchWidth -
|
||||
(actions.length == 2 ? otherActionWidth : 0);
|
||||
final availablePositions = rightWidth ~/ otherActionWidth;
|
||||
debugPrint(
|
||||
"dynamic action count:${dynamicActions.length}, available positions: $availablePositions");
|
||||
|
||||
if (availablePositions < dynamicActions.length &&
|
||||
dynamicActions.length > 1) {
|
||||
if (availablePositions < 2) {
|
||||
actions.addAll([
|
||||
dropDown(dynamicActions),
|
||||
]);
|
||||
} else {
|
||||
actions.addAll([
|
||||
...dynamicActions.sublist(0, availablePositions - 1),
|
||||
dropDown(dynamicActions.sublist(availablePositions - 1)),
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
actions.addAll(dynamicActions);
|
||||
}
|
||||
return actions;
|
||||
}
|
||||
}
|
||||
|
||||
class PeerSearchBar extends StatefulWidget {
|
||||
@@ -839,3 +939,14 @@ Widget _hoverAction(
|
||||
child: Container(padding: padding, child: child))),
|
||||
);
|
||||
}
|
||||
|
||||
class PullDownMenuEntryImpl extends StatelessWidget
|
||||
implements PullDownMenuEntry {
|
||||
final Widget child;
|
||||
const PullDownMenuEntryImpl({super.key, required this.child});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import 'dart:collection';
|
||||
import 'package:dynamic_layouts/dynamic_layouts.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hbb/desktop/widgets/scroll_wrapper.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:visibility_detector/visibility_detector.dart';
|
||||
@@ -95,6 +96,8 @@ class _PeersViewState extends State<_PeersView> with WindowListener {
|
||||
return width;
|
||||
}();
|
||||
|
||||
final _scrollController = ScrollController();
|
||||
|
||||
_PeersViewState() {
|
||||
_startCheckOnlines();
|
||||
}
|
||||
@@ -176,31 +179,52 @@ class _PeersViewState extends State<_PeersView> with WindowListener {
|
||||
return FutureBuilder<List<Peer>>(
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
final peers = snapshot.data!;
|
||||
var peers = snapshot.data!;
|
||||
if (peers.length > 1000) peers = peers.sublist(0, 1000);
|
||||
gFFI.peerTabModel.setCurrentTabCachedPeers(peers);
|
||||
final child = DynamicGridView.builder(
|
||||
gridDelegate: SliverGridDelegateWithWrapping(
|
||||
mainAxisSpacing: space / 2, crossAxisSpacing: space),
|
||||
itemCount: peers.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
final visibilityChild = VisibilityDetector(
|
||||
key: ValueKey(_cardId(peers[index].id)),
|
||||
onVisibilityChanged: onVisibilityChanged,
|
||||
child: widget.peerCardBuilder(peers[index]),
|
||||
);
|
||||
return isDesktop
|
||||
? Obx(
|
||||
() => SizedBox(
|
||||
width: 220,
|
||||
height: peerCardUiType.value == PeerUiType.grid
|
||||
? 140
|
||||
: 42,
|
||||
child: visibilityChild,
|
||||
),
|
||||
)
|
||||
: SizedBox(width: mobileWidth, child: visibilityChild);
|
||||
},
|
||||
);
|
||||
buildOnePeer(Peer peer) {
|
||||
final visibilityChild = VisibilityDetector(
|
||||
key: ValueKey(_cardId(peer.id)),
|
||||
onVisibilityChanged: onVisibilityChanged,
|
||||
child: widget.peerCardBuilder(peer),
|
||||
);
|
||||
return isDesktop
|
||||
? Obx(
|
||||
() => SizedBox(
|
||||
width: 220,
|
||||
height:
|
||||
peerCardUiType.value == PeerUiType.grid ? 140 : 42,
|
||||
child: visibilityChild,
|
||||
),
|
||||
)
|
||||
: SizedBox(width: mobileWidth, child: visibilityChild);
|
||||
}
|
||||
|
||||
final Widget child;
|
||||
if (isMobile) {
|
||||
child = DynamicGridView.builder(
|
||||
gridDelegate: SliverGridDelegateWithWrapping(
|
||||
mainAxisSpacing: space / 2, crossAxisSpacing: space),
|
||||
itemCount: peers.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return buildOnePeer(peers[index]);
|
||||
},
|
||||
);
|
||||
} else {
|
||||
child = DesktopScrollWrapper(
|
||||
scrollController: _scrollController,
|
||||
child: DynamicGridView.builder(
|
||||
controller: _scrollController,
|
||||
physics: DraggableNeverScrollableScrollPhysics(),
|
||||
gridDelegate: SliverGridDelegateWithWrapping(
|
||||
mainAxisSpacing: space / 2, crossAxisSpacing: space),
|
||||
itemCount: peers.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return buildOnePeer(peers[index]);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (updateEvent == UpdateEvent.load) {
|
||||
_curPeers.clear();
|
||||
_curPeers.addAll(peers.map((e) => e.id));
|
||||
|
||||
@@ -93,6 +93,7 @@ class _RawTouchGestureDetectorRegionState
|
||||
return;
|
||||
}
|
||||
if (handleTouch) {
|
||||
// Desktop or mobile "Touch mode"
|
||||
ffi.cursorModel.move(d.localPosition.dx, d.localPosition.dy);
|
||||
inputModel.tapDown(MouseButtons.left);
|
||||
}
|
||||
@@ -112,7 +113,10 @@ class _RawTouchGestureDetectorRegionState
|
||||
if (lastDeviceKind != PointerDeviceKind.touch) {
|
||||
return;
|
||||
}
|
||||
inputModel.tap(MouseButtons.left);
|
||||
if (!handleTouch) {
|
||||
// Mobile, "Mouse mode"
|
||||
inputModel.tap(MouseButtons.left);
|
||||
}
|
||||
}
|
||||
|
||||
onDoubleTapDown(TapDownDetails d) {
|
||||
|
||||
@@ -49,7 +49,8 @@ class TToggleMenu {
|
||||
handleOsPasswordEditIcon(
|
||||
SessionID sessionId, OverlayDialogManager dialogManager) {
|
||||
isEditOsPassword = true;
|
||||
showSetOSPassword(sessionId, false, dialogManager, null, () => isEditOsPassword = false);
|
||||
showSetOSPassword(
|
||||
sessionId, false, dialogManager, null, () => isEditOsPassword = false);
|
||||
}
|
||||
|
||||
handleOsPasswordAction(
|
||||
@@ -62,7 +63,8 @@ handleOsPasswordAction(
|
||||
await bind.sessionGetOption(sessionId: sessionId, arg: 'os-password') ??
|
||||
'';
|
||||
if (password.isEmpty) {
|
||||
showSetOSPassword(sessionId, true, dialogManager, password, () => isEditOsPassword = false);
|
||||
showSetOSPassword(sessionId, true, dialogManager, password,
|
||||
() => isEditOsPassword = false);
|
||||
} else {
|
||||
bind.sessionInputOsPassword(sessionId: sessionId, value: password);
|
||||
}
|
||||
@@ -76,7 +78,7 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
|
||||
|
||||
List<TTextMenu> v = [];
|
||||
// elevation
|
||||
if (ffi.elevationModel.showRequestMenu) {
|
||||
if (perms['keyboard'] != false && ffi.elevationModel.showRequestMenu) {
|
||||
v.add(
|
||||
TTextMenu(
|
||||
child: Text(translate('Request Elevation')),
|
||||
|
||||
Reference in New Issue
Block a user