Merge pull request #2446 from 21pages/tab

hide/reorder peer card
This commit is contained in:
RustDesk 2022-12-04 21:33:02 +08:00 committed by GitHub
commit f649f8dbcd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 282 additions and 111 deletions

View File

@ -215,18 +215,15 @@ class MyTheme {
}
static void changeDarkMode(ThemeMode mode) {
final preference = getThemeModePreference();
if (preference != mode) {
Get.changeThemeMode(mode);
if (desktopType == DesktopType.main) {
if (mode == ThemeMode.system) {
bind.mainSetLocalOption(key: kCommConfKeyTheme, value: '');
} else {
bind.mainSetLocalOption(
key: kCommConfKeyTheme, value: mode.toShortString());
}
Get.changeThemeMode(mode);
if (desktopType == DesktopType.main) {
bind.mainChangeTheme(dark: currentThemeMode().toShortString());
}
bind.mainChangeTheme(dark: currentThemeMode().toShortString());
}
}

View File

@ -90,7 +90,7 @@ class _AddressBookState extends State<AddressBook> {
Text(translate(error)),
TextButton(
onPressed: () {
setState(() {});
gFFI.abModel.pullAb();
},
child: Text(translate("Retry")))
],

View File

@ -1,64 +1,107 @@
import 'dart:convert';
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/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/tabbar_widget.dart';
import 'package:flutter_hbb/desktop/widgets/material_mod_popup_menu.dart'
as mod_menu;
import 'package:get/get.dart';
import '../../common.dart';
import '../../models/platform_model.dart';
class PeerTabPage extends StatefulWidget {
final List<String> tabs;
final List<Widget> children;
const PeerTabPage({required this.tabs, required this.children, Key? key})
: super(key: key);
const PeerTabPage({Key? key}) : super(key: key);
@override
State<PeerTabPage> createState() => _PeerTabPageState();
}
class _TabEntry {
final String name;
final Widget widget;
final Function() load;
_TabEntry(this.name, this.widget, this.load);
}
class _PeerTabPageState extends State<PeerTabPage>
with SingleTickerProviderStateMixin {
final RxInt _tabIndex = 0.obs;
late final RxInt tabHiddenFlag;
late final RxString currentTab;
late final RxList<String> visibleOrderedTabs;
final List<_TabEntry> entries = [
_TabEntry(
'Recent Sessions',
RecentPeersView(
menuPadding: kDesktopMenuPadding,
),
bind.mainLoadRecentPeers),
_TabEntry(
'Favorites',
FavoritePeersView(
menuPadding: kDesktopMenuPadding,
),
bind.mainLoadFavPeers),
_TabEntry(
'Discovered',
DiscoveredPeersView(
menuPadding: kDesktopMenuPadding,
),
bind.mainDiscover),
_TabEntry(
'Address Book',
const AddressBook(
menuPadding: kDesktopMenuPadding,
),
() => {}),
];
@override
void initState() {
setPeer();
super.initState();
}
setPeer() {
final index = bind.getLocalFlutterConfig(k: 'peer-tab-index');
if (index != '') {
_tabIndex.value = int.parse(index);
tabHiddenFlag = (int.tryParse(
bind.getLocalFlutterConfig(k: 'hidden-peer-card'),
radix: 2) ??
0)
.obs;
currentTab = bind.getLocalFlutterConfig(k: 'current-peer-tab').obs;
visibleOrderedTabs = entries
.where((e) => !isTabHidden(e.name))
.map((e) => e.name)
.toList()
.obs;
try {
final json = jsonDecode(bind.getLocalFlutterConfig(k: 'peer-tab-order'));
if (json is List) {
final List<String> list = json.map((e) => e.toString()).toList();
if (list.length == visibleOrderedTabs.length &&
visibleOrderedTabs.every((e) => list.contains(e))) {
visibleOrderedTabs.value = list;
}
}
} catch (e) {
debugPrint('$e');
}
adjustTab();
final uiType = bind.getLocalFlutterConfig(k: 'peer-card-ui-type');
if (uiType != '') {
peerCardUiType.value = int.parse(uiType) == PeerUiType.list.index
? PeerUiType.list
: PeerUiType.grid;
}
super.initState();
}
// hard code for now
Future<void> _handleTabSelection(int index) async {
_tabIndex.value = index;
await bind.setLocalFlutterConfig(k: 'peer-tab-index', v: index.toString());
switch (index) {
case 0:
bind.mainLoadRecentPeers();
break;
case 1:
bind.mainLoadFavPeers();
break;
case 2:
bind.mainDiscover();
break;
case 3:
/// AddressBook initState will refresh ab state
break;
}
Future<void> handleTabSelection(String tabName) async {
currentTab.value = tabName;
await bind.setLocalFlutterConfig(k: 'current-peer-tab', v: tabName);
entries.firstWhereOrNull((e) => e.name == tabName)?.load();
}
@override
@ -80,8 +123,9 @@ class _PeerTabPageState extends State<PeerTabPage>
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(child: _createSwitchBar(context)),
const SizedBox(width: 10),
Expanded(
child: visibleContextMenuListener(
_createSwitchBar(context))),
const PeerSearchBar(),
Offstage(
offstage: !isDesktop,
@ -97,16 +141,34 @@ class _PeerTabPageState extends State<PeerTabPage>
Widget _createSwitchBar(BuildContext context) {
final textColor = Theme.of(context).textTheme.titleLarge?.color;
return ListView(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
controller: ScrollController(),
children: super.widget.tabs.asMap().entries.map((t) {
return Obx(() => InkWell(
return Obx(() {
int indexCounter = -1;
return ReorderableListView(
buildDefaultDragHandles: false,
onReorder: (oldIndex, newIndex) {
var list = visibleOrderedTabs.toList();
if (oldIndex < newIndex) {
newIndex -= 1;
}
final String item = list.removeAt(oldIndex);
list.insert(newIndex, item);
bind.setLocalFlutterConfig(
k: 'peer-tab-order', v: jsonEncode(list));
visibleOrderedTabs.value = list;
},
scrollDirection: Axis.horizontal,
shrinkWrap: true,
scrollController: ScrollController(),
children: visibleOrderedTabs.map((t) {
indexCounter++;
return ReorderableDragStartListener(
key: ValueKey(t),
index: indexCounter,
child: InkWell(
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 8),
decoration: BoxDecoration(
color: _tabIndex.value == t.key
color: currentTab.value == t
? Theme.of(context).backgroundColor
: null,
borderRadius: BorderRadius.circular(isDesktop ? 2 : 6),
@ -114,27 +176,30 @@ class _PeerTabPageState extends State<PeerTabPage>
child: Align(
alignment: Alignment.center,
child: Text(
t.value,
translate(t),
textAlign: TextAlign.center,
style: TextStyle(
height: 1,
fontSize: 14,
color:
_tabIndex.value == t.key ? textColor : textColor
?..withOpacity(0.5)),
color: currentTab.value == t ? textColor : textColor
?..withOpacity(0.5)),
),
)),
onTap: () async => await _handleTabSelection(t.key),
));
}).toList());
onTap: () async => await handleTabSelection(t),
),
);
}).toList());
});
}
Widget _createPeersView() {
final verticalMargin = isDesktop ? 12.0 : 6.0;
return Expanded(
child: Obx(() => widget
.children[_tabIndex.value]) //: (to) => _tabIndex.value = to)
.marginSymmetric(vertical: verticalMargin),
child: Obx(() =>
entries.firstWhereOrNull((e) => e.name == currentTab.value)?.widget ??
visibleContextMenuListener(Center(
child: Text(translate('Right click to select tabs')),
))).marginSymmetric(vertical: verticalMargin),
);
}
@ -167,6 +232,87 @@ class _PeerTabPageState extends State<PeerTabPage>
.toList(),
);
}
bool isTabHidden(String name) {
int index = entries.indexWhere((e) => e.name == name);
if (index >= 0) {
return tabHiddenFlag & (1 << index) != 0;
}
assert(false);
return false;
}
adjustTab() {
if (visibleOrderedTabs.isNotEmpty) {
if (!visibleOrderedTabs.contains(currentTab.value)) {
handleTabSelection(visibleOrderedTabs[0]);
}
} else {
currentTab.value = '';
}
}
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 List<MenuEntryBase> menu = entries.asMap().entries.map((e) {
int bitMask = 1 << e.key;
return MenuEntrySwitch(
switchType: SwitchType.scheckbox,
text: translate(e.value.name),
getter: () async {
return tabHiddenFlag.value & bitMask == 0;
},
setter: (show) async {
if (show) {
tabHiddenFlag.value &= ~bitMask;
} else {
tabHiddenFlag.value |= bitMask;
}
await bind.setLocalFlutterConfig(
k: 'hidden-peer-card', v: tabHiddenFlag.value.toRadixString(2));
visibleOrderedTabs.removeWhere((e) => isTabHidden(e));
visibleOrderedTabs.addAll(entries
.where((e) =>
!visibleOrderedTabs.contains(e.name) &&
!isTabHidden(e.name))
.map((e) => e.name)
.toList());
await bind.setLocalFlutterConfig(
k: 'peer-tab-order', v: jsonEncode(visibleOrderedTabs));
cancelFunc();
adjustTab();
});
}).toList();
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 {

View File

@ -113,7 +113,7 @@ class _ConnectionPageState extends State<ConnectionPage>
delegate: SliverChildListDelegate([
Row(
children: [
_buildRemoteIDTextField(context),
Flexible(child: _buildRemoteIDTextField(context)),
],
).marginOnly(top: 22),
SizedBox(height: 12),
@ -121,28 +121,7 @@ class _ConnectionPageState extends State<ConnectionPage>
])),
SliverFillRemaining(
hasScrollBody: false,
child: PeerTabPage(
tabs: [
translate('Recent Sessions'),
translate('Favorites'),
translate('Discovered'),
translate('Address Book')
],
children: [
RecentPeersView(
menuPadding: kDesktopMenuPadding,
),
FavoritePeersView(
menuPadding: kDesktopMenuPadding,
),
DiscoveredPeersView(
menuPadding: kDesktopMenuPadding,
),
const AddressBook(
menuPadding: kDesktopMenuPadding,
),
],
).paddingOnly(right: 12.0),
child: PeerTabPage().paddingOnly(right: 12.0),
)
],
).paddingOnly(left: 12.0),
@ -258,9 +237,8 @@ class _ConnectionPageState extends State<ConnectionPage>
),
),
);
return Center(
child: Container(
constraints: const BoxConstraints(maxWidth: 600), child: w));
return Container(
constraints: const BoxConstraints(maxWidth: 600), child: w);
}
Widget buildStatus() {

View File

@ -238,7 +238,7 @@ Widget buildConnectionCard(Client client) {
key: ValueKey(client.id),
children: [
_CmHeader(client: client),
client.isFileTransfer || client.disconnected
client.type_() != ClientType.remote || client.disconnected
? Offstage()
: _PrivilegeBoard(client: client),
Expanded(
@ -376,7 +376,7 @@ class _CmHeaderState extends State<_CmHeader>
),
),
Offstage(
offstage: !client.authorized || client.isFileTransfer,
offstage: !client.authorized || client.type_() != ClientType.remote,
child: IconButton(
onPressed: () => checkClickTime(
client.id, () => gFFI.chatModel.toggleCMChatPage(client.id)),
@ -510,7 +510,9 @@ class _CmControlPanel extends StatelessWidget {
buildAuthorized(BuildContext context) {
final bool canElevate = bind.cmCanElevate();
final model = Provider.of<ServerModel>(context);
final showElevation = canElevate && model.showElevation;
final showElevation = canElevate &&
model.showElevation &&
client.type_() == ClientType.remote;
return Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
@ -560,7 +562,9 @@ class _CmControlPanel extends StatelessWidget {
buildUnAuthorized(BuildContext context) {
final bool canElevate = bind.cmCanElevate();
final model = Provider.of<ServerModel>(context);
final showElevation = canElevate && model.showElevation;
final showElevation = canElevate &&
model.showElevation &&
client.type_() == ClientType.remote;
final showAccept = model.approveMode != 'password';
return Column(
mainAxisAlignment: MainAxisAlignment.end,

View File

@ -75,20 +75,7 @@ class _ConnectionPageState extends State<ConnectionPage> {
])),
SliverFillRemaining(
hasScrollBody: false,
child: PeerTabPage(
tabs: [
translate('Recent Sessions'),
translate('Favorites'),
translate('Discovered'),
translate('Address Book')
],
children: [
RecentPeersView(),
FavoritePeersView(),
DiscoveredPeersView(),
const AddressBook(),
],
),
child: PeerTabPage(),
)
],
).marginOnly(top: 2, left: 10, right: 10);

View File

@ -34,13 +34,20 @@ class AbModel {
if (resp.body.isNotEmpty && resp.body.toLowerCase() != "null") {
Map<String, dynamic> json = jsonDecode(resp.body);
if (json.containsKey('error')) {
abError = json['error'];
abError.value = json['error'];
} else if (json.containsKey('data')) {
final data = jsonDecode(json['data']);
tags.value = data['tags'];
peers.clear();
for (final peer in data['peers']) {
peers.add(Peer.fromJson(peer));
if (data != null) {
tags.clear();
peers.clear();
if (data['tags'] is List) {
tags.value = data['tags'];
}
if (data['peers'] is List) {
for (final peer in data['peers']) {
peers.add(Peer.fromJson(peer));
}
}
}
}
return resp.body;

View File

@ -581,10 +581,17 @@ class ServerModel with ChangeNotifier {
}
}
enum ClientType {
remote,
file,
portForward,
}
class Client {
int id = 0; // client connections inner count id
bool authorized = false;
bool isFileTransfer = false;
String portForward = "";
String name = "";
String peerId = ""; // peer user's id,show at app
bool keyboard = false;
@ -604,6 +611,7 @@ class Client {
id = json['id'];
authorized = json['authorized'];
isFileTransfer = json['is_file_transfer'];
portForward = json['port_forward'];
name = json['name'];
peerId = json['peer_id'];
keyboard = json['keyboard'];
@ -620,6 +628,7 @@ class Client {
data['id'] = id;
data['is_start'] = authorized;
data['is_file_transfer'] = isFileTransfer;
data['port_forward'] = portForward;
data['name'] = name;
data['peer_id'] = peerId;
data['keyboard'] = keyboard;
@ -631,6 +640,16 @@ class Client {
data['disconnected'] = disconnected;
return data;
}
ClientType type_() {
if (isFileTransfer) {
return ClientType.file;
} else if (portForward.isNotEmpty) {
return ClientType.portForward;
} else {
return ClientType.remote;
}
}
}
String getLoginDialogTag(int id) {

View File

@ -398,5 +398,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Hide connection management window", ""),
("hide_cm_tip", ""),
("wayland_experiment_tip", ""),
("Right click to select tabs", ""),
].iter().cloned().collect();
}

View File

@ -398,5 +398,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Hide connection management window", "隐藏连接管理窗口"),
("hide_cm_tip", "在只允许密码连接并且只用固定密码的情况下才允许隐藏"),
("wayland_experiment_tip", ""),
("Right click to select tabs", "右键选择选项卡"),
].iter().cloned().collect();
}

View File

@ -398,5 +398,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Hide connection management window", ""),
("hide_cm_tip", ""),
("wayland_experiment_tip", ""),
("Right click to select tabs", ""),
].iter().cloned().collect();
}

View File

@ -398,5 +398,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Hide connection management window", ""),
("hide_cm_tip", ""),
("wayland_experiment_tip", ""),
("Right click to select tabs", ""),
].iter().cloned().collect();
}

View File

@ -398,5 +398,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Hide connection management window", "Fenster zur Verwaltung der Verbindung verstecken"),
("hide_cm_tip", "Dies ist nur möglich, wenn der Zugriff nur über ein permanentes Passwort erfolgt."), // Sehr unklar. Muss noch angepasst werden. Original: Allow hiding only if accepting sessions via password and using pernament passw"),
("wayland_experiment_tip", ""),
("Right click to select tabs", ""),
].iter().cloned().collect();
}

View File

@ -398,5 +398,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Hide connection management window", ""),
("hide_cm_tip", ""),
("wayland_experiment_tip", ""),
("Right click to select tabs", ""),
].iter().cloned().collect();
}

View File

@ -398,5 +398,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Hide connection management window", "Ocultar ventana de gestión de conexión"),
("hide_cm_tip", "Permitir ocultar solo si se aceptan sesiones a través de contraseña y usando contraseña permanente"),
("wayland_experiment_tip", ""),
("Right click to select tabs", ""),
].iter().cloned().collect();
}

View File

@ -398,5 +398,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Hide connection management window", "پنهان کردن پنجره مدیریت اتصال"),
("hide_cm_tip", "فقط در صورت پذیرفتن جلسات از طریق رمز عبور و استفاده از رمز عبور دائمی، مخفی شدن مجاز است"),
("wayland_experiment_tip", ""),
("Right click to select tabs", ""),
].iter().cloned().collect();
}

View File

@ -398,5 +398,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Hide connection management window", "Masquer la fenêtre de gestion des connexions"),
("hide_cm_tip", "Autoriser le masquage uniquement si vous acceptez des sessions via un mot de passe et utilisez un mot de passe permanent"),
("wayland_experiment_tip", ""),
("Right click to select tabs", ""),
].iter().cloned().collect();
}

View File

@ -397,6 +397,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Request access to your device", "Αίτημα πρόσβασης στη συσκευή σας"),
("Hide connection management window", "Απόκρυψη παραθύρου διαχείρισης σύνδεσης"),
("hide_cm_tip", "Να επιτρέπεται η απόκρυψη, μόνο εάν αποδέχεστε συνδέσεις μέσω κωδικού πρόσβασης και χρησιμοποιείτε μόνιμο κωδικό πρόσβασης"),
("wayland_experiment_tip", ""),
("Right click to select tabs", ""),
].iter().cloned().collect();
}

View File

@ -398,5 +398,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Hide connection management window", ""),
("hide_cm_tip", ""),
("wayland_experiment_tip", ""),
("Right click to select tabs", ""),
].iter().cloned().collect();
}

View File

@ -398,5 +398,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Hide connection management window", ""),
("hide_cm_tip", ""),
("wayland_experiment_tip", ""),
("Right click to select tabs", ""),
].iter().cloned().collect();
}

View File

@ -398,5 +398,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Hide connection management window", "Nascondi la finestra di gestione delle connessioni"),
("hide_cm_tip", "Permetti di nascondere solo se si accettano sessioni con password permanente"),
("wayland_experiment_tip", ""),
("Right click to select tabs", ""),
].iter().cloned().collect();
}

View File

@ -398,5 +398,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Hide connection management window", ""),
("hide_cm_tip", ""),
("wayland_experiment_tip", ""),
("Right click to select tabs", ""),
].iter().cloned().collect();
}

View File

@ -398,5 +398,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Hide connection management window", ""),
("hide_cm_tip", ""),
("wayland_experiment_tip", ""),
("Right click to select tabs", ""),
].iter().cloned().collect();
}

View File

@ -398,5 +398,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Hide connection management window", ""),
("hide_cm_tip", ""),
("wayland_experiment_tip", ""),
("Right click to select tabs", ""),
].iter().cloned().collect();
}

View File

@ -398,5 +398,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Hide connection management window", ""),
("hide_cm_tip", ""),
("wayland_experiment_tip", ""),
("Right click to select tabs", ""),
].iter().cloned().collect();
}

View File

@ -398,5 +398,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Hide connection management window", ""),
("hide_cm_tip", ""),
("wayland_experiment_tip", ""),
("Right click to select tabs", ""),
].iter().cloned().collect();
}

View File

@ -398,5 +398,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Hide connection management window", ""),
("hide_cm_tip", ""),
("wayland_experiment_tip", ""),
("Right click to select tabs", ""),
].iter().cloned().collect();
}

View File

@ -398,5 +398,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Hide connection management window", "Скрывать окно управления соединениями"),
("hide_cm_tip", "Разрешать скрытие случае, если принимаются сеансы по паролю или используется постоянный пароль"),
("wayland_experiment_tip", "Поддержка Wayland находится на экспериментальной стадии, используйте X11, если вам требуется автоматический доступ."),
("Right click to select tabs", ""),
].iter().cloned().collect();
}

View File

@ -398,5 +398,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Hide connection management window", ""),
("hide_cm_tip", ""),
("wayland_experiment_tip", ""),
("Right click to select tabs", ""),
].iter().cloned().collect();
}

View File

@ -398,5 +398,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Hide connection management window", "Fshih dritaren e menaxhimit të lidhjes"),
("hide_cm_tip", "Kjo është e mundur vetëm nëse aksesi bëhet nëpërmjet një fjalëkalimi të përhershëm"),
("wayland_experiment_tip", ""),
("Right click to select tabs", ""),
].iter().cloned().collect();
}

View File

@ -398,5 +398,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Hide connection management window", "Göm hanteringsfönster"),
("hide_cm_tip", "Tillåt att gömma endast om accepterande sessioner med lösenord och permanenta lösenord"),
("wayland_experiment_tip", ""),
("Right click to select tabs", ""),
].iter().cloned().collect();
}

View File

@ -398,5 +398,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Hide connection management window", ""),
("hide_cm_tip", ""),
("wayland_experiment_tip", ""),
("Right click to select tabs", ""),
].iter().cloned().collect();
}

View File

@ -398,5 +398,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Hide connection management window", "Bağlantı yönetimi penceresini gizle"),
("hide_cm_tip", ""),
("wayland_experiment_tip", ""),
("Right click to select tabs", ""),
].iter().cloned().collect();
}

View File

@ -398,5 +398,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Hide connection management window", "隱藏連接管理窗口"),
("hide_cm_tip", "在只允許密碼連接並且只用固定密碼的情況下才允許隱藏"),
("wayland_experiment_tip", ""),
("Right click to select tabs", "右鍵選擇選項卡"),
].iter().cloned().collect();
}

View File

@ -398,5 +398,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Hide connection management window", ""),
("hide_cm_tip", ""),
("wayland_experiment_tip", ""),
("Right click to select tabs", ""),
].iter().cloned().collect();
}

View File

@ -398,5 +398,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Hide connection management window", ""),
("hide_cm_tip", ""),
("wayland_experiment_tip", ""),
("Right click to select tabs", ""),
].iter().cloned().collect();
}

View File

@ -29,7 +29,7 @@ class Body: Reactor.Component
};
var right_style = show_chat ? "" : "display: none";
var disconnected = c.disconnected;
var show_elevation_btn = handler.can_elevate() && show_elevation;
var show_elevation_btn = handler.can_elevate() && show_elevation && !c.is_file_transfer && c.port_forward.length == 0;
var show_accept_btn = handler.get_option('approve-mode') != 'password';
// below size:* is work around for Linux, it alreayd set in css, but not work, shit sciter
return <div .content style="size:*">

View File

@ -200,7 +200,7 @@ impl<T: InvokeUiSession> Session<T> {
h265 = h265 && encoding_265;
return (h264, h265);
}
#[allow(dead_code)]
#[allow(unreachable_code)]
(false, false)
}
@ -1211,7 +1211,13 @@ impl<T: InvokeUiSession> Interface for Session<T> {
input_os_password(p, true, self.clone());
}
let current = &pi.displays[pi.current_display as usize];
self.set_display(current.x, current.y, current.width, current.height, current.cursor_embeded);
self.set_display(
current.x,
current.y,
current.width,
current.height,
current.cursor_embeded,
);
}
self.update_privacy_mode();
// Save recent peers, then push event to flutter. So flutter can refresh peer page.