mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-04-08 07:11:29 +03:00
device group (#10781)
1. Rename `Group` tab to `Accessible devices` 2. Add accessible device groups at the top of search list 3. option `preset-device-group-name` and command line `--assign --device_group_name` Signed-off-by: 21pages <sunboeasy@gmail.com>
This commit is contained in:
BIN
flutter/assets/device_group.ttf
Normal file
BIN
flutter/assets/device_group.ttf
Normal file
Binary file not shown.
@@ -103,6 +103,8 @@ enum DesktopType {
|
|||||||
class IconFont {
|
class IconFont {
|
||||||
static const _family1 = 'Tabbar';
|
static const _family1 = 'Tabbar';
|
||||||
static const _family2 = 'PeerSearchbar';
|
static const _family2 = 'PeerSearchbar';
|
||||||
|
static const _family3 = 'AddressBook';
|
||||||
|
static const _family4 = 'DeviceGroup';
|
||||||
IconFont._();
|
IconFont._();
|
||||||
|
|
||||||
static const IconData max = IconData(0xe606, fontFamily: _family1);
|
static const IconData max = IconData(0xe606, fontFamily: _family1);
|
||||||
@@ -113,8 +115,11 @@ class IconFont {
|
|||||||
static const IconData menu = IconData(0xe628, fontFamily: _family1);
|
static const IconData menu = IconData(0xe628, fontFamily: _family1);
|
||||||
static const IconData search = IconData(0xe6a4, fontFamily: _family2);
|
static const IconData search = IconData(0xe6a4, fontFamily: _family2);
|
||||||
static const IconData roundClose = IconData(0xe6ed, fontFamily: _family2);
|
static const IconData roundClose = IconData(0xe6ed, fontFamily: _family2);
|
||||||
static const IconData addressBook =
|
static const IconData addressBook = IconData(0xe602, fontFamily: _family3);
|
||||||
IconData(0xe602, fontFamily: "AddressBook");
|
static const IconData deviceGroupOutline =
|
||||||
|
IconData(0xe623, fontFamily: _family4);
|
||||||
|
static const IconData deviceGroupFill =
|
||||||
|
IconData(0xe748, fontFamily: _family4);
|
||||||
}
|
}
|
||||||
|
|
||||||
class ColorThemeExtension extends ThemeExtension<ColorThemeExtension> {
|
class ColorThemeExtension extends ThemeExtension<ColorThemeExtension> {
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ class PeerPayload {
|
|||||||
int? status;
|
int? status;
|
||||||
String user = '';
|
String user = '';
|
||||||
String user_name = '';
|
String user_name = '';
|
||||||
|
String? device_group_name;
|
||||||
String note = '';
|
String note = '';
|
||||||
|
|
||||||
PeerPayload.fromJson(Map<String, dynamic> json)
|
PeerPayload.fromJson(Map<String, dynamic> json)
|
||||||
@@ -75,6 +76,7 @@ class PeerPayload {
|
|||||||
status = json['status'],
|
status = json['status'],
|
||||||
user = json['user'] ?? '',
|
user = json['user'] ?? '',
|
||||||
user_name = json['user_name'] ?? '',
|
user_name = json['user_name'] ?? '',
|
||||||
|
device_group_name = json['device_group_name'] ?? '',
|
||||||
note = json['note'] ?? '';
|
note = json['note'] ?? '';
|
||||||
|
|
||||||
static Peer toPeer(PeerPayload p) {
|
static Peer toPeer(PeerPayload p) {
|
||||||
@@ -84,6 +86,7 @@ class PeerPayload {
|
|||||||
"username": p.info['username'] ?? '',
|
"username": p.info['username'] ?? '',
|
||||||
"platform": _platform(p.info['os']),
|
"platform": _platform(p.info['os']),
|
||||||
"hostname": p.info['device_name'],
|
"hostname": p.info['device_name'],
|
||||||
|
"device_group_name": p.device_group_name,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,3 +268,19 @@ class AbTag {
|
|||||||
: name = json['name'] ?? '',
|
: name = json['name'] ?? '',
|
||||||
color = json['color'] ?? '';
|
color = json['color'] ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DeviceGroupPayload {
|
||||||
|
String name;
|
||||||
|
|
||||||
|
DeviceGroupPayload(this.name);
|
||||||
|
|
||||||
|
DeviceGroupPayload.fromJson(Map<String, dynamic> json)
|
||||||
|
: name = json['name'] ?? '';
|
||||||
|
|
||||||
|
Map<String, dynamic> toGroupCacheJson() {
|
||||||
|
final Map<String, dynamic> map = {
|
||||||
|
'name': name,
|
||||||
|
};
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -20,8 +20,11 @@ class MyGroup extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _MyGroupState extends State<MyGroup> {
|
class _MyGroupState extends State<MyGroup> {
|
||||||
RxString get selectedUser => gFFI.groupModel.selectedUser;
|
RxBool get isSelectedDeviceGroup => gFFI.groupModel.isSelectedDeviceGroup;
|
||||||
RxString get searchUserText => gFFI.groupModel.searchUserText;
|
RxString get selectedAccessibleItemName =>
|
||||||
|
gFFI.groupModel.selectedAccessibleItemName;
|
||||||
|
RxString get searchAccessibleItemNameText =>
|
||||||
|
gFFI.groupModel.searchAccessibleItemNameText;
|
||||||
static TextEditingController searchUserController = TextEditingController();
|
static TextEditingController searchUserController = TextEditingController();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -72,7 +75,7 @@ class _MyGroupState extends State<MyGroup> {
|
|||||||
child: Container(
|
child: Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
height: double.infinity,
|
height: double.infinity,
|
||||||
child: _buildUserContacts(),
|
child: _buildLeftList(),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
@@ -105,7 +108,7 @@ class _MyGroupState extends State<MyGroup> {
|
|||||||
_buildLeftHeader(),
|
_buildLeftHeader(),
|
||||||
Container(
|
Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
child: _buildUserContacts(),
|
child: _buildLeftList(),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -130,7 +133,7 @@ class _MyGroupState extends State<MyGroup> {
|
|||||||
child: TextField(
|
child: TextField(
|
||||||
controller: searchUserController,
|
controller: searchUserController,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
searchUserText.value = value;
|
searchAccessibleItemNameText.value = value;
|
||||||
},
|
},
|
||||||
textAlignVertical: TextAlignVertical.center,
|
textAlignVertical: TextAlignVertical.center,
|
||||||
style: TextStyle(fontSize: fontSize),
|
style: TextStyle(fontSize: fontSize),
|
||||||
@@ -150,20 +153,30 @@ class _MyGroupState extends State<MyGroup> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildUserContacts() {
|
Widget _buildLeftList() {
|
||||||
return Obx(() {
|
return Obx(() {
|
||||||
final items = gFFI.groupModel.users.where((p0) {
|
final userItems = gFFI.groupModel.users.where((p0) {
|
||||||
if (searchUserText.isNotEmpty) {
|
if (searchAccessibleItemNameText.isNotEmpty) {
|
||||||
return p0.name
|
return p0.name
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.contains(searchUserText.value.toLowerCase());
|
.contains(searchAccessibleItemNameText.value.toLowerCase());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}).toList();
|
||||||
|
final deviceGroupItems = gFFI.groupModel.deviceGroups.where((p0) {
|
||||||
|
if (searchAccessibleItemNameText.isNotEmpty) {
|
||||||
|
return p0.name
|
||||||
|
.toLowerCase()
|
||||||
|
.contains(searchAccessibleItemNameText.value.toLowerCase());
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}).toList();
|
}).toList();
|
||||||
listView(bool isPortrait) => ListView.builder(
|
listView(bool isPortrait) => ListView.builder(
|
||||||
shrinkWrap: isPortrait,
|
shrinkWrap: isPortrait,
|
||||||
itemCount: items.length,
|
itemCount: deviceGroupItems.length + userItems.length,
|
||||||
itemBuilder: (context, index) => _buildUserItem(items[index]));
|
itemBuilder: (context, index) => index < deviceGroupItems.length
|
||||||
|
? _buildDeviceGroupItem(deviceGroupItems[index])
|
||||||
|
: _buildUserItem(userItems[index - deviceGroupItems.length]));
|
||||||
var maxHeight = max(MediaQuery.of(context).size.height / 6, 100.0);
|
var maxHeight = max(MediaQuery.of(context).size.height / 6, 100.0);
|
||||||
return Obx(() => stateGlobal.isPortrait.isFalse
|
return Obx(() => stateGlobal.isPortrait.isFalse
|
||||||
? listView(false)
|
? listView(false)
|
||||||
@@ -174,14 +187,16 @@ class _MyGroupState extends State<MyGroup> {
|
|||||||
Widget _buildUserItem(UserPayload user) {
|
Widget _buildUserItem(UserPayload user) {
|
||||||
final username = user.name;
|
final username = user.name;
|
||||||
return InkWell(onTap: () {
|
return InkWell(onTap: () {
|
||||||
if (selectedUser.value != username) {
|
isSelectedDeviceGroup.value = false;
|
||||||
selectedUser.value = username;
|
if (selectedAccessibleItemName.value != username) {
|
||||||
|
selectedAccessibleItemName.value = username;
|
||||||
} else {
|
} else {
|
||||||
selectedUser.value = '';
|
selectedAccessibleItemName.value = '';
|
||||||
}
|
}
|
||||||
}, child: Obx(
|
}, child: Obx(
|
||||||
() {
|
() {
|
||||||
bool selected = selectedUser.value == username;
|
bool selected = !isSelectedDeviceGroup.value &&
|
||||||
|
selectedAccessibleItemName.value == username;
|
||||||
final isMe = username == gFFI.userModel.userName.value;
|
final isMe = username == gFFI.userModel.userName.value;
|
||||||
final colorMe = MyTheme.color(context).me!;
|
final colorMe = MyTheme.color(context).me!;
|
||||||
return Container(
|
return Container(
|
||||||
@@ -238,4 +253,43 @@ class _MyGroupState extends State<MyGroup> {
|
|||||||
},
|
},
|
||||||
)).marginSymmetric(horizontal: 12).marginOnly(bottom: 6);
|
)).marginSymmetric(horizontal: 12).marginOnly(bottom: 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildDeviceGroupItem(DeviceGroupPayload deviceGroup) {
|
||||||
|
final name = deviceGroup.name;
|
||||||
|
return InkWell(onTap: () {
|
||||||
|
isSelectedDeviceGroup.value = true;
|
||||||
|
if (selectedAccessibleItemName.value != name) {
|
||||||
|
selectedAccessibleItemName.value = name;
|
||||||
|
} else {
|
||||||
|
selectedAccessibleItemName.value = '';
|
||||||
|
}
|
||||||
|
}, child: Obx(
|
||||||
|
() {
|
||||||
|
bool selected = isSelectedDeviceGroup.value &&
|
||||||
|
selectedAccessibleItemName.value == name;
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: selected ? MyTheme.color(context).highlight : null,
|
||||||
|
border: Border(
|
||||||
|
bottom: BorderSide(
|
||||||
|
width: 0.7,
|
||||||
|
color: Theme.of(context).dividerColor.withOpacity(0.1))),
|
||||||
|
),
|
||||||
|
child: Container(
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
|
child: Icon(IconFont.deviceGroupOutline,
|
||||||
|
color: MyTheme.accent, size: 19),
|
||||||
|
).marginOnly(right: 4),
|
||||||
|
Expanded(child: Text(name)),
|
||||||
|
],
|
||||||
|
).paddingSymmetric(vertical: 4),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)).marginSymmetric(horizontal: 12).marginOnly(bottom: 6);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -562,14 +562,23 @@ class MyGroupPeerView extends BasePeersView {
|
|||||||
);
|
);
|
||||||
|
|
||||||
static bool filter(Peer peer) {
|
static bool filter(Peer peer) {
|
||||||
if (gFFI.groupModel.searchUserText.isNotEmpty) {
|
if (gFFI.groupModel.searchAccessibleItemNameText.isNotEmpty) {
|
||||||
if (!peer.loginName.contains(gFFI.groupModel.searchUserText)) {
|
if (!peer.loginName
|
||||||
|
.contains(gFFI.groupModel.searchAccessibleItemNameText)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (gFFI.groupModel.selectedUser.isNotEmpty) {
|
if (gFFI.groupModel.selectedAccessibleItemName.isNotEmpty) {
|
||||||
if (gFFI.groupModel.selectedUser.value != peer.loginName) {
|
if (gFFI.groupModel.isSelectedDeviceGroup.value) {
|
||||||
return false;
|
if (gFFI.groupModel.selectedAccessibleItemName.value !=
|
||||||
|
peer.device_group_name) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (gFFI.groupModel.selectedAccessibleItemName.value !=
|
||||||
|
peer.loginName) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -350,6 +350,7 @@ class _ConnectionPageState extends State<ConnectionPage>
|
|||||||
rdpPort: '',
|
rdpPort: '',
|
||||||
rdpUsername: '',
|
rdpUsername: '',
|
||||||
loginName: '',
|
loginName: '',
|
||||||
|
device_group_name: '',
|
||||||
);
|
);
|
||||||
_autocompleteOpts = [emptyPeer];
|
_autocompleteOpts = [emptyPeer];
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -174,6 +174,7 @@ class _ConnectionPageState extends State<ConnectionPage> {
|
|||||||
rdpPort: '',
|
rdpPort: '',
|
||||||
rdpUsername: '',
|
rdpUsername: '',
|
||||||
loginName: '',
|
loginName: '',
|
||||||
|
device_group_name: '',
|
||||||
);
|
);
|
||||||
_autocompleteOpts = [emptyPeer];
|
_autocompleteOpts = [emptyPeer];
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -12,16 +12,18 @@ import '../utils/http_service.dart' as http;
|
|||||||
class GroupModel {
|
class GroupModel {
|
||||||
final RxBool groupLoading = false.obs;
|
final RxBool groupLoading = false.obs;
|
||||||
final RxString groupLoadError = "".obs;
|
final RxString groupLoadError = "".obs;
|
||||||
|
final RxList<DeviceGroupPayload> deviceGroups = RxList.empty(growable: true);
|
||||||
final RxList<UserPayload> users = RxList.empty(growable: true);
|
final RxList<UserPayload> users = RxList.empty(growable: true);
|
||||||
final RxList<Peer> peers = RxList.empty(growable: true);
|
final RxList<Peer> peers = RxList.empty(growable: true);
|
||||||
final RxString selectedUser = ''.obs;
|
final RxBool isSelectedDeviceGroup = false.obs;
|
||||||
final RxString searchUserText = ''.obs;
|
final RxString selectedAccessibleItemName = ''.obs;
|
||||||
|
final RxString searchAccessibleItemNameText = ''.obs;
|
||||||
WeakReference<FFI> parent;
|
WeakReference<FFI> parent;
|
||||||
var initialized = false;
|
var initialized = false;
|
||||||
var _cacheLoadOnceFlag = false;
|
var _cacheLoadOnceFlag = false;
|
||||||
var _statusCode = 200;
|
var _statusCode = 200;
|
||||||
|
|
||||||
bool get emtpy => users.isEmpty && peers.isEmpty;
|
bool get emtpy => deviceGroups.isEmpty && users.isEmpty && peers.isEmpty;
|
||||||
|
|
||||||
late final Peers peersModel;
|
late final Peers peersModel;
|
||||||
|
|
||||||
@@ -55,6 +57,12 @@ class GroupModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _pull() async {
|
Future<void> _pull() async {
|
||||||
|
List<DeviceGroupPayload> tmpDeviceGroups = List.empty(growable: true);
|
||||||
|
if (!await _getDeviceGroups(tmpDeviceGroups)) {
|
||||||
|
// old hbbs doesn't support this api
|
||||||
|
// return;
|
||||||
|
}
|
||||||
|
tmpDeviceGroups.sort((a, b) => a.name.compareTo(b.name));
|
||||||
List<UserPayload> tmpUsers = List.empty(growable: true);
|
List<UserPayload> tmpUsers = List.empty(growable: true);
|
||||||
if (!await _getUsers(tmpUsers)) {
|
if (!await _getUsers(tmpUsers)) {
|
||||||
return;
|
return;
|
||||||
@@ -63,6 +71,7 @@ class GroupModel {
|
|||||||
if (!await _getPeers(tmpPeers)) {
|
if (!await _getPeers(tmpPeers)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
deviceGroups.value = tmpDeviceGroups;
|
||||||
// me first
|
// me first
|
||||||
var index = tmpUsers
|
var index = tmpUsers
|
||||||
.indexWhere((user) => user.name == gFFI.userModel.userName.value);
|
.indexWhere((user) => user.name == gFFI.userModel.userName.value);
|
||||||
@@ -71,8 +80,9 @@ class GroupModel {
|
|||||||
tmpUsers.insert(0, user);
|
tmpUsers.insert(0, user);
|
||||||
}
|
}
|
||||||
users.value = tmpUsers;
|
users.value = tmpUsers;
|
||||||
if (!users.any((u) => u.name == selectedUser.value)) {
|
if (!users.any((u) => u.name == selectedAccessibleItemName.value) &&
|
||||||
selectedUser.value = '';
|
!deviceGroups.any((d) => d.name == selectedAccessibleItemName.value)) {
|
||||||
|
selectedAccessibleItemName.value = '';
|
||||||
}
|
}
|
||||||
// recover online
|
// recover online
|
||||||
final oldOnlineIDs = peers.where((e) => e.online).map((e) => e.id).toList();
|
final oldOnlineIDs = peers.where((e) => e.online).map((e) => e.id).toList();
|
||||||
@@ -84,6 +94,63 @@ class GroupModel {
|
|||||||
groupLoadError.value = '';
|
groupLoadError.value = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<bool> _getDeviceGroups(
|
||||||
|
List<DeviceGroupPayload> tmpDeviceGroups) async {
|
||||||
|
final api = "${await bind.mainGetApiServer()}/api/device-group/accessible";
|
||||||
|
try {
|
||||||
|
var uri0 = Uri.parse(api);
|
||||||
|
final pageSize = 100;
|
||||||
|
var total = 0;
|
||||||
|
int current = 0;
|
||||||
|
do {
|
||||||
|
current += 1;
|
||||||
|
var uri = Uri(
|
||||||
|
scheme: uri0.scheme,
|
||||||
|
host: uri0.host,
|
||||||
|
path: uri0.path,
|
||||||
|
port: uri0.port,
|
||||||
|
queryParameters: {
|
||||||
|
'current': current.toString(),
|
||||||
|
'pageSize': pageSize.toString(),
|
||||||
|
});
|
||||||
|
final resp = await http.get(uri, headers: getHttpHeaders());
|
||||||
|
_statusCode = resp.statusCode;
|
||||||
|
Map<String, dynamic> json =
|
||||||
|
_jsonDecodeResp(utf8.decode(resp.bodyBytes), resp.statusCode);
|
||||||
|
if (json.containsKey('error')) {
|
||||||
|
throw json['error'];
|
||||||
|
}
|
||||||
|
if (resp.statusCode != 200) {
|
||||||
|
throw 'HTTP ${resp.statusCode}';
|
||||||
|
}
|
||||||
|
if (json.containsKey('total')) {
|
||||||
|
if (total == 0) total = json['total'];
|
||||||
|
if (json.containsKey('data')) {
|
||||||
|
final data = json['data'];
|
||||||
|
if (data is List) {
|
||||||
|
for (final user in data) {
|
||||||
|
final u = DeviceGroupPayload.fromJson(user);
|
||||||
|
int index = tmpDeviceGroups.indexWhere((e) => e.name == u.name);
|
||||||
|
if (index < 0) {
|
||||||
|
tmpDeviceGroups.add(u);
|
||||||
|
} else {
|
||||||
|
tmpDeviceGroups[index] = u;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (current * pageSize < total);
|
||||||
|
return true;
|
||||||
|
} catch (err) {
|
||||||
|
debugPrint('get accessible device groups: $err');
|
||||||
|
// old hbbs doesn't support this api
|
||||||
|
// groupLoadError.value =
|
||||||
|
// '${translate('pull_group_failed_tip')}: ${translate(err.toString())}';
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Future<bool> _getUsers(List<UserPayload> tmpUsers) async {
|
Future<bool> _getUsers(List<UserPayload> tmpUsers) async {
|
||||||
final api = "${await bind.mainGetApiServer()}/api/users";
|
final api = "${await bind.mainGetApiServer()}/api/users";
|
||||||
try {
|
try {
|
||||||
@@ -225,6 +292,7 @@ class GroupModel {
|
|||||||
try {
|
try {
|
||||||
final map = (<String, dynamic>{
|
final map = (<String, dynamic>{
|
||||||
"access_token": bind.mainGetLocalOption(key: 'access_token'),
|
"access_token": bind.mainGetLocalOption(key: 'access_token'),
|
||||||
|
"device_groups": deviceGroups.map((e) => e.toGroupCacheJson()).toList(),
|
||||||
"users": users.map((e) => e.toGroupCacheJson()).toList(),
|
"users": users.map((e) => e.toGroupCacheJson()).toList(),
|
||||||
'peers': peers.map((e) => e.toGroupCacheJson()).toList()
|
'peers': peers.map((e) => e.toGroupCacheJson()).toList()
|
||||||
});
|
});
|
||||||
@@ -244,8 +312,14 @@ class GroupModel {
|
|||||||
if (groupLoading.value) return;
|
if (groupLoading.value) return;
|
||||||
final data = jsonDecode(cache);
|
final data = jsonDecode(cache);
|
||||||
if (data == null || data['access_token'] != access_token) return;
|
if (data == null || data['access_token'] != access_token) return;
|
||||||
|
deviceGroups.clear();
|
||||||
users.clear();
|
users.clear();
|
||||||
peers.clear();
|
peers.clear();
|
||||||
|
if (data['device_groups'] is List) {
|
||||||
|
for (var u in data['device_groups']) {
|
||||||
|
deviceGroups.add(DeviceGroupPayload.fromJson(u));
|
||||||
|
}
|
||||||
|
}
|
||||||
if (data['users'] is List) {
|
if (data['users'] is List) {
|
||||||
for (var u in data['users']) {
|
for (var u in data['users']) {
|
||||||
users.add(UserPayload.fromJson(u));
|
users.add(UserPayload.fromJson(u));
|
||||||
@@ -263,9 +337,10 @@ class GroupModel {
|
|||||||
|
|
||||||
reset() async {
|
reset() async {
|
||||||
groupLoadError.value = '';
|
groupLoadError.value = '';
|
||||||
|
deviceGroups.clear();
|
||||||
users.clear();
|
users.clear();
|
||||||
peers.clear();
|
peers.clear();
|
||||||
selectedUser.value = '';
|
selectedAccessibleItemName.value = '';
|
||||||
await bind.mainClearGroup();
|
await bind.mainClearGroup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ class Peer {
|
|||||||
String rdpUsername;
|
String rdpUsername;
|
||||||
bool online = false;
|
bool online = false;
|
||||||
String loginName; //login username
|
String loginName; //login username
|
||||||
|
String device_group_name;
|
||||||
bool? sameServer;
|
bool? sameServer;
|
||||||
|
|
||||||
String getId() {
|
String getId() {
|
||||||
@@ -41,6 +42,7 @@ class Peer {
|
|||||||
rdpPort = json['rdpPort'] ?? '',
|
rdpPort = json['rdpPort'] ?? '',
|
||||||
rdpUsername = json['rdpUsername'] ?? '',
|
rdpUsername = json['rdpUsername'] ?? '',
|
||||||
loginName = json['loginName'] ?? '',
|
loginName = json['loginName'] ?? '',
|
||||||
|
device_group_name = json['device_group_name'] ?? '',
|
||||||
sameServer = json['same_server'];
|
sameServer = json['same_server'];
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
@@ -57,6 +59,7 @@ class Peer {
|
|||||||
"rdpPort": rdpPort,
|
"rdpPort": rdpPort,
|
||||||
"rdpUsername": rdpUsername,
|
"rdpUsername": rdpUsername,
|
||||||
'loginName': loginName,
|
'loginName': loginName,
|
||||||
|
'device_group_name': device_group_name,
|
||||||
'same_server': sameServer,
|
'same_server': sameServer,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -83,6 +86,7 @@ class Peer {
|
|||||||
"hostname": hostname,
|
"hostname": hostname,
|
||||||
"platform": platform,
|
"platform": platform,
|
||||||
"login_name": loginName,
|
"login_name": loginName,
|
||||||
|
"device_group_name": device_group_name,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,6 +103,7 @@ class Peer {
|
|||||||
required this.rdpPort,
|
required this.rdpPort,
|
||||||
required this.rdpUsername,
|
required this.rdpUsername,
|
||||||
required this.loginName,
|
required this.loginName,
|
||||||
|
required this.device_group_name,
|
||||||
this.sameServer,
|
this.sameServer,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -116,6 +121,7 @@ class Peer {
|
|||||||
rdpPort: '',
|
rdpPort: '',
|
||||||
rdpUsername: '',
|
rdpUsername: '',
|
||||||
loginName: '',
|
loginName: '',
|
||||||
|
device_group_name: '',
|
||||||
);
|
);
|
||||||
bool equal(Peer other) {
|
bool equal(Peer other) {
|
||||||
return id == other.id &&
|
return id == other.id &&
|
||||||
@@ -129,6 +135,7 @@ class Peer {
|
|||||||
forceAlwaysRelay == other.forceAlwaysRelay &&
|
forceAlwaysRelay == other.forceAlwaysRelay &&
|
||||||
rdpPort == other.rdpPort &&
|
rdpPort == other.rdpPort &&
|
||||||
rdpUsername == other.rdpUsername &&
|
rdpUsername == other.rdpUsername &&
|
||||||
|
device_group_name == other.device_group_name &&
|
||||||
loginName == other.loginName;
|
loginName == other.loginName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,6 +153,7 @@ class Peer {
|
|||||||
rdpPort: other.rdpPort,
|
rdpPort: other.rdpPort,
|
||||||
rdpUsername: other.rdpUsername,
|
rdpUsername: other.rdpUsername,
|
||||||
loginName: other.loginName,
|
loginName: other.loginName,
|
||||||
|
device_group_name: other.device_group_name,
|
||||||
sameServer: other.sameServer);
|
sameServer: other.sameServer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,14 +28,14 @@ class PeerTabModel with ChangeNotifier {
|
|||||||
'Favorites',
|
'Favorites',
|
||||||
'Discovered',
|
'Discovered',
|
||||||
'Address book',
|
'Address book',
|
||||||
'Group',
|
'Accessible devices',
|
||||||
];
|
];
|
||||||
static const List<IconData> icons = [
|
static const List<IconData> icons = [
|
||||||
Icons.access_time_filled,
|
Icons.access_time_filled,
|
||||||
Icons.star,
|
Icons.star,
|
||||||
Icons.explore,
|
Icons.explore,
|
||||||
IconFont.addressBook,
|
IconFont.addressBook,
|
||||||
Icons.group,
|
IconFont.deviceGroupFill,
|
||||||
];
|
];
|
||||||
List<bool> isEnabled = List.from([
|
List<bool> isEnabled = List.from([
|
||||||
true,
|
true,
|
||||||
|
|||||||
@@ -161,6 +161,9 @@ flutter:
|
|||||||
- family: AddressBook
|
- family: AddressBook
|
||||||
fonts:
|
fonts:
|
||||||
- asset: assets/address_book.ttf
|
- asset: assets/address_book.ttf
|
||||||
|
- family: DeviceGroup
|
||||||
|
fonts:
|
||||||
|
- asset: assets/device_group.ttf
|
||||||
|
|
||||||
# An image asset can refer to one or more resolution-specific "variants", see
|
# An image asset can refer to one or more resolution-specific "variants", see
|
||||||
# https://flutter.dev/assets-and-images/#resolution-aware.
|
# https://flutter.dev/assets-and-images/#resolution-aware.
|
||||||
|
|||||||
Submodule libs/hbb_common updated: 97266d7c18...8b6700a33f
@@ -427,15 +427,26 @@ pub fn core_main() -> Option<Vec<String>> {
|
|||||||
if pos < max {
|
if pos < max {
|
||||||
address_book_tag = Some(args[pos + 1].to_owned());
|
address_book_tag = Some(args[pos + 1].to_owned());
|
||||||
}
|
}
|
||||||
|
let mut device_group_name = None;
|
||||||
|
let pos = args
|
||||||
|
.iter()
|
||||||
|
.position(|x| x == "--device_group_name")
|
||||||
|
.unwrap_or(max);
|
||||||
|
if pos < max {
|
||||||
|
device_group_name = Some(args[pos + 1].to_owned());
|
||||||
|
}
|
||||||
let mut body = serde_json::json!({
|
let mut body = serde_json::json!({
|
||||||
"id": id,
|
"id": id,
|
||||||
"uuid": uuid,
|
"uuid": uuid,
|
||||||
});
|
});
|
||||||
let header = "Authorization: Bearer ".to_owned() + &token;
|
let header = "Authorization: Bearer ".to_owned() + &token;
|
||||||
if user_name.is_none() && strategy_name.is_none() && address_book_name.is_none()
|
if user_name.is_none()
|
||||||
|
&& strategy_name.is_none()
|
||||||
|
&& address_book_name.is_none()
|
||||||
|
&& device_group_name.is_none()
|
||||||
{
|
{
|
||||||
println!(
|
println!(
|
||||||
"--user_name or --strategy_name or --address_book_name is required!"
|
"--user_name or --strategy_name or --address_book_name or --device_group_name is required!"
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
if let Some(name) = user_name {
|
if let Some(name) = user_name {
|
||||||
@@ -450,6 +461,9 @@ pub fn core_main() -> Option<Vec<String>> {
|
|||||||
body["address_book_tag"] = serde_json::json!(name);
|
body["address_book_tag"] = serde_json::json!(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if let Some(name) = device_group_name {
|
||||||
|
body["device_group_name"] = serde_json::json!(name);
|
||||||
|
}
|
||||||
let url = crate::ui_interface::get_api_server() + "/api/devices/cli";
|
let url = crate::ui_interface::get_api_server() + "/api/devices/cli";
|
||||||
match crate::post_request_sync(url, body.to_string(), &header) {
|
match crate::post_request_sync(url, body.to_string(), &header) {
|
||||||
Err(err) => println!("{}", err),
|
Err(err) => println!("{}", err),
|
||||||
|
|||||||
@@ -99,6 +99,10 @@ async fn start_hbbs_sync_async() {
|
|||||||
if !strategy_name.is_empty() {
|
if !strategy_name.is_empty() {
|
||||||
v[keys::OPTION_PRESET_STRATEGY_NAME] = json!(strategy_name);
|
v[keys::OPTION_PRESET_STRATEGY_NAME] = json!(strategy_name);
|
||||||
}
|
}
|
||||||
|
let device_group_name = get_builtin_option(keys::OPTION_PRESET_DEVICE_GROUP_NAME);
|
||||||
|
if !device_group_name.is_empty() {
|
||||||
|
v[keys::OPTION_PRESET_DEVICE_GROUP_NAME] = json!(device_group_name);
|
||||||
|
}
|
||||||
match crate::post_request(url.replace("heartbeat", "sysinfo"), v.to_string(), "").await {
|
match crate::post_request(url.replace("heartbeat", "sysinfo"), v.to_string(), "").await {
|
||||||
Ok(x) => {
|
Ok(x) => {
|
||||||
if x == "SYSINFO_UPDATED" {
|
if x == "SYSINFO_UPDATED" {
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", ""),
|
("Update client clipboard", ""),
|
||||||
("Untagged", ""),
|
("Untagged", ""),
|
||||||
("new-version-of-{}-tip", ""),
|
("new-version-of-{}-tip", ""),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", ""),
|
("Update client clipboard", ""),
|
||||||
("Untagged", ""),
|
("Untagged", ""),
|
||||||
("new-version-of-{}-tip", ""),
|
("new-version-of-{}-tip", ""),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", ""),
|
("Update client clipboard", ""),
|
||||||
("Untagged", ""),
|
("Untagged", ""),
|
||||||
("new-version-of-{}-tip", ""),
|
("new-version-of-{}-tip", ""),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", ""),
|
("Update client clipboard", ""),
|
||||||
("Untagged", ""),
|
("Untagged", ""),
|
||||||
("new-version-of-{}-tip", ""),
|
("new-version-of-{}-tip", ""),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", "更新客户端的粘贴板"),
|
("Update client clipboard", "更新客户端的粘贴板"),
|
||||||
("Untagged", "无标签"),
|
("Untagged", "无标签"),
|
||||||
("new-version-of-{}-tip", "{} 版本更新"),
|
("new-version-of-{}-tip", "{} 版本更新"),
|
||||||
|
("Accessible devices", "可访问的设备"),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", ""),
|
("Update client clipboard", ""),
|
||||||
("Untagged", ""),
|
("Untagged", ""),
|
||||||
("new-version-of-{}-tip", ""),
|
("new-version-of-{}-tip", ""),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", ""),
|
("Update client clipboard", ""),
|
||||||
("Untagged", ""),
|
("Untagged", ""),
|
||||||
("new-version-of-{}-tip", ""),
|
("new-version-of-{}-tip", ""),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", "Client-Zwischenablage aktualisieren"),
|
("Update client clipboard", "Client-Zwischenablage aktualisieren"),
|
||||||
("Untagged", "Unmarkiert"),
|
("Untagged", "Unmarkiert"),
|
||||||
("new-version-of-{}-tip", "Es ist eine neue Version von {} verfügbar"),
|
("new-version-of-{}-tip", "Es ist eine neue Version von {} verfügbar"),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", "Ενημέρωση απομακρισμένου προχείρου"),
|
("Update client clipboard", "Ενημέρωση απομακρισμένου προχείρου"),
|
||||||
("Untagged", "Χωρίς ετικέτα"),
|
("Untagged", "Χωρίς ετικέτα"),
|
||||||
("new-version-of-{}-tip", "Υπάρχει διαθέσιμη νέα έκδοση του {}"),
|
("new-version-of-{}-tip", "Υπάρχει διαθέσιμη νέα έκδοση του {}"),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", ""),
|
("Update client clipboard", ""),
|
||||||
("Untagged", ""),
|
("Untagged", ""),
|
||||||
("new-version-of-{}-tip", ""),
|
("new-version-of-{}-tip", ""),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", "Actualizar portapapeles del cliente"),
|
("Update client clipboard", "Actualizar portapapeles del cliente"),
|
||||||
("Untagged", "Sin itiquetar"),
|
("Untagged", "Sin itiquetar"),
|
||||||
("new-version-of-{}-tip", "Hay una nueva versión de {} disponible"),
|
("new-version-of-{}-tip", "Hay una nueva versión de {} disponible"),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", ""),
|
("Update client clipboard", ""),
|
||||||
("Untagged", ""),
|
("Untagged", ""),
|
||||||
("new-version-of-{}-tip", ""),
|
("new-version-of-{}-tip", ""),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", ""),
|
("Update client clipboard", ""),
|
||||||
("Untagged", ""),
|
("Untagged", ""),
|
||||||
("new-version-of-{}-tip", ""),
|
("new-version-of-{}-tip", ""),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", ""),
|
("Update client clipboard", ""),
|
||||||
("Untagged", ""),
|
("Untagged", ""),
|
||||||
("new-version-of-{}-tip", ""),
|
("new-version-of-{}-tip", ""),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", ""),
|
("Update client clipboard", ""),
|
||||||
("Untagged", ""),
|
("Untagged", ""),
|
||||||
("new-version-of-{}-tip", ""),
|
("new-version-of-{}-tip", ""),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", ""),
|
("Update client clipboard", ""),
|
||||||
("Untagged", ""),
|
("Untagged", ""),
|
||||||
("new-version-of-{}-tip", ""),
|
("new-version-of-{}-tip", ""),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", ""),
|
("Update client clipboard", ""),
|
||||||
("Untagged", ""),
|
("Untagged", ""),
|
||||||
("new-version-of-{}-tip", ""),
|
("new-version-of-{}-tip", ""),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", "A kliens vágólapjának frissítése"),
|
("Update client clipboard", "A kliens vágólapjának frissítése"),
|
||||||
("Untagged", "Címkézetlen"),
|
("Untagged", "Címkézetlen"),
|
||||||
("new-version-of-{}-tip", "A(z) {} új verziója"),
|
("new-version-of-{}-tip", "A(z) {} új verziója"),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", ""),
|
("Update client clipboard", ""),
|
||||||
("Untagged", ""),
|
("Untagged", ""),
|
||||||
("new-version-of-{}-tip", ""),
|
("new-version-of-{}-tip", ""),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", "Aggiorna appunti client"),
|
("Update client clipboard", "Aggiorna appunti client"),
|
||||||
("Untagged", "Senza tag"),
|
("Untagged", "Senza tag"),
|
||||||
("new-version-of-{}-tip", "È disponibile una nuova versione di {}"),
|
("new-version-of-{}-tip", "È disponibile una nuova versione di {}"),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", ""),
|
("Update client clipboard", ""),
|
||||||
("Untagged", ""),
|
("Untagged", ""),
|
||||||
("new-version-of-{}-tip", ""),
|
("new-version-of-{}-tip", ""),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", "클라이언트 클립보드 업데이트"),
|
("Update client clipboard", "클라이언트 클립보드 업데이트"),
|
||||||
("Untagged", "태그 없음"),
|
("Untagged", "태그 없음"),
|
||||||
("new-version-of-{}-tip", "{} 의 새로운 버전이 출시되었습니다."),
|
("new-version-of-{}-tip", "{} 의 새로운 버전이 출시되었습니다."),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", ""),
|
("Update client clipboard", ""),
|
||||||
("Untagged", ""),
|
("Untagged", ""),
|
||||||
("new-version-of-{}-tip", ""),
|
("new-version-of-{}-tip", ""),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", ""),
|
("Update client clipboard", ""),
|
||||||
("Untagged", ""),
|
("Untagged", ""),
|
||||||
("new-version-of-{}-tip", ""),
|
("new-version-of-{}-tip", ""),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", "Atjaunināt klienta starpliktuvi"),
|
("Update client clipboard", "Atjaunināt klienta starpliktuvi"),
|
||||||
("Untagged", "Neatzīmēts"),
|
("Untagged", "Neatzīmēts"),
|
||||||
("new-version-of-{}-tip", "Ir pieejama jauna {} versija"),
|
("new-version-of-{}-tip", "Ir pieejama jauna {} versija"),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", ""),
|
("Update client clipboard", ""),
|
||||||
("Untagged", ""),
|
("Untagged", ""),
|
||||||
("new-version-of-{}-tip", ""),
|
("new-version-of-{}-tip", ""),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", "Klembord van client bijwerken"),
|
("Update client clipboard", "Klembord van client bijwerken"),
|
||||||
("Untagged", "Ongemarkeerd"),
|
("Untagged", "Ongemarkeerd"),
|
||||||
("new-version-of-{}-tip", "Er is een nieuwe versie van {} beschikbaar"),
|
("new-version-of-{}-tip", "Er is een nieuwe versie van {} beschikbaar"),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", "Uaktualnij schowek klienta"),
|
("Update client clipboard", "Uaktualnij schowek klienta"),
|
||||||
("Untagged", ""),
|
("Untagged", ""),
|
||||||
("new-version-of-{}-tip", ""),
|
("new-version-of-{}-tip", ""),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", ""),
|
("Update client clipboard", ""),
|
||||||
("Untagged", ""),
|
("Untagged", ""),
|
||||||
("new-version-of-{}-tip", ""),
|
("new-version-of-{}-tip", ""),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", ""),
|
("Update client clipboard", ""),
|
||||||
("Untagged", ""),
|
("Untagged", ""),
|
||||||
("new-version-of-{}-tip", ""),
|
("new-version-of-{}-tip", ""),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", ""),
|
("Update client clipboard", ""),
|
||||||
("Untagged", ""),
|
("Untagged", ""),
|
||||||
("new-version-of-{}-tip", ""),
|
("new-version-of-{}-tip", ""),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", "Обновить буфер обмена клиента"),
|
("Update client clipboard", "Обновить буфер обмена клиента"),
|
||||||
("Untagged", "Без метки"),
|
("Untagged", "Без метки"),
|
||||||
("new-version-of-{}-tip", "Доступна новая версия {}"),
|
("new-version-of-{}-tip", "Доступна новая версия {}"),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", ""),
|
("Update client clipboard", ""),
|
||||||
("Untagged", ""),
|
("Untagged", ""),
|
||||||
("new-version-of-{}-tip", ""),
|
("new-version-of-{}-tip", ""),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", "Osveži odjemalčevo odložišče"),
|
("Update client clipboard", "Osveži odjemalčevo odložišče"),
|
||||||
("Untagged", "Neoznačeno"),
|
("Untagged", "Neoznačeno"),
|
||||||
("new-version-of-{}-tip", "Na voljo je nova različica {}"),
|
("new-version-of-{}-tip", "Na voljo je nova različica {}"),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", ""),
|
("Update client clipboard", ""),
|
||||||
("Untagged", ""),
|
("Untagged", ""),
|
||||||
("new-version-of-{}-tip", ""),
|
("new-version-of-{}-tip", ""),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", ""),
|
("Update client clipboard", ""),
|
||||||
("Untagged", ""),
|
("Untagged", ""),
|
||||||
("new-version-of-{}-tip", ""),
|
("new-version-of-{}-tip", ""),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", ""),
|
("Update client clipboard", ""),
|
||||||
("Untagged", ""),
|
("Untagged", ""),
|
||||||
("new-version-of-{}-tip", ""),
|
("new-version-of-{}-tip", ""),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", ""),
|
("Update client clipboard", ""),
|
||||||
("Untagged", ""),
|
("Untagged", ""),
|
||||||
("new-version-of-{}-tip", ""),
|
("new-version-of-{}-tip", ""),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", ""),
|
("Update client clipboard", ""),
|
||||||
("Untagged", ""),
|
("Untagged", ""),
|
||||||
("new-version-of-{}-tip", ""),
|
("new-version-of-{}-tip", ""),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", ""),
|
("Update client clipboard", ""),
|
||||||
("Untagged", ""),
|
("Untagged", ""),
|
||||||
("new-version-of-{}-tip", ""),
|
("new-version-of-{}-tip", ""),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", "更新客戶端的剪貼簿"),
|
("Update client clipboard", "更新客戶端的剪貼簿"),
|
||||||
("Untagged", "無標籤"),
|
("Untagged", "無標籤"),
|
||||||
("new-version-of-{}-tip", "有新版本的 {} 可用"),
|
("new-version-of-{}-tip", "有新版本的 {} 可用"),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", "Оновити буфер обміну клієнта"),
|
("Update client clipboard", "Оновити буфер обміну клієнта"),
|
||||||
("Untagged", "Без міток"),
|
("Untagged", "Без міток"),
|
||||||
("new-version-of-{}-tip", "Доступна нова версія {}"),
|
("new-version-of-{}-tip", "Доступна нова версія {}"),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,5 +656,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Update client clipboard", ""),
|
("Update client clipboard", ""),
|
||||||
("Untagged", ""),
|
("Untagged", ""),
|
||||||
("new-version-of-{}-tip", ""),
|
("new-version-of-{}-tip", ""),
|
||||||
|
("Accessible devices", ""),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user