mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-04-14 21:31:30 +03:00
Compare commits
1 Commits
tcp-proxy
...
890282e385
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
890282e385 |
@@ -26,6 +26,7 @@ enum UserStatus { kDisabled, kNormal, kUnverified }
|
|||||||
class UserPayload {
|
class UserPayload {
|
||||||
String name = '';
|
String name = '';
|
||||||
String displayName = '';
|
String displayName = '';
|
||||||
|
String avatar = '';
|
||||||
String email = '';
|
String email = '';
|
||||||
String note = '';
|
String note = '';
|
||||||
String? verifier;
|
String? verifier;
|
||||||
@@ -35,6 +36,7 @@ class UserPayload {
|
|||||||
UserPayload.fromJson(Map<String, dynamic> json)
|
UserPayload.fromJson(Map<String, dynamic> json)
|
||||||
: name = json['name'] ?? '',
|
: name = json['name'] ?? '',
|
||||||
displayName = json['display_name'] ?? '',
|
displayName = json['display_name'] ?? '',
|
||||||
|
avatar = json['avatar'] ?? '',
|
||||||
email = json['email'] ?? '',
|
email = json['email'] ?? '',
|
||||||
note = json['note'] ?? '',
|
note = json['note'] ?? '',
|
||||||
verifier = json['verifier'],
|
verifier = json['verifier'],
|
||||||
@@ -49,6 +51,7 @@ class UserPayload {
|
|||||||
final Map<String, dynamic> map = {
|
final Map<String, dynamic> map = {
|
||||||
'name': name,
|
'name': name,
|
||||||
'display_name': displayName,
|
'display_name': displayName,
|
||||||
|
'avatar': avatar,
|
||||||
'status': status == UserStatus.kDisabled
|
'status': status == UserStatus.kDisabled
|
||||||
? 0
|
? 0
|
||||||
: status == UserStatus.kUnverified
|
: status == UserStatus.kUnverified
|
||||||
|
|||||||
@@ -2026,28 +2026,79 @@ class _AccountState extends State<_Account> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget useInfo() {
|
Widget useInfo() {
|
||||||
text(String key, String value) {
|
|
||||||
return Align(
|
|
||||||
alignment: Alignment.centerLeft,
|
|
||||||
child: SelectionArea(child: Text('${translate(key)}: $value'))
|
|
||||||
.marginSymmetric(vertical: 4),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Obx(() => Offstage(
|
return Obx(() => Offstage(
|
||||||
offstage: gFFI.userModel.userName.value.isEmpty,
|
offstage: gFFI.userModel.userName.value.isEmpty,
|
||||||
child: Column(
|
child: Container(
|
||||||
children: [
|
padding: const EdgeInsets.all(12),
|
||||||
if (gFFI.userModel.displayName.value.trim().isNotEmpty &&
|
decoration: BoxDecoration(
|
||||||
gFFI.userModel.displayName.value.trim() !=
|
color: Theme.of(context).colorScheme.surfaceContainerHighest,
|
||||||
gFFI.userModel.userName.value.trim())
|
borderRadius: BorderRadius.circular(10),
|
||||||
text('Display Name', gFFI.userModel.displayName.value.trim()),
|
),
|
||||||
text('Username', gFFI.userModel.userName.value),
|
child: Builder(builder: (context) {
|
||||||
// text('Group', gFFI.groupModel.groupName.value),
|
final avatarWidget = _buildUserAvatar();
|
||||||
],
|
return Row(
|
||||||
|
children: [
|
||||||
|
if (avatarWidget != null) avatarWidget,
|
||||||
|
if (avatarWidget != null) const SizedBox(width: 12),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
gFFI.userModel.displayNameOrUserName,
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 2),
|
||||||
|
SelectionArea(
|
||||||
|
child: Text(
|
||||||
|
'@${gFFI.userModel.userName.value}',
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 13,
|
||||||
|
color: Theme.of(context).textTheme.bodySmall?.color,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}),
|
||||||
),
|
),
|
||||||
)).marginOnly(left: 18, top: 16);
|
)).marginOnly(left: 18, top: 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget? _buildUserAvatar() {
|
||||||
|
final avatar = gFFI.userModel.avatar.value.trim();
|
||||||
|
if (avatar.isEmpty) return null;
|
||||||
|
const radius = 22.0;
|
||||||
|
if (avatar.startsWith('data:image/')) {
|
||||||
|
final comma = avatar.indexOf(',');
|
||||||
|
if (comma > 0) {
|
||||||
|
try {
|
||||||
|
return CircleAvatar(
|
||||||
|
radius: radius,
|
||||||
|
backgroundImage: MemoryImage(base64Decode(avatar.substring(comma + 1))),
|
||||||
|
);
|
||||||
|
} catch (_) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (avatar.startsWith('http://') || avatar.startsWith('https://')) {
|
||||||
|
return CircleAvatar(
|
||||||
|
radius: radius,
|
||||||
|
backgroundImage: NetworkImage(avatar),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _Checkbox extends StatefulWidget {
|
class _Checkbox extends StatefulWidget {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// original cm window in Sciter version.
|
// original cm window in Sciter version.
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@@ -462,23 +463,7 @@ class _CmHeaderState extends State<_CmHeader>
|
|||||||
child: Row(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Container(
|
_buildClientAvatar().marginOnly(right: 10.0),
|
||||||
width: 70,
|
|
||||||
height: 70,
|
|
||||||
alignment: Alignment.center,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: str2color(client.name),
|
|
||||||
borderRadius: BorderRadius.circular(15.0),
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
client.name[0],
|
|
||||||
style: TextStyle(
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: Colors.white,
|
|
||||||
fontSize: 55,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
).marginOnly(right: 10.0),
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
@@ -582,6 +567,60 @@ class _CmHeaderState extends State<_CmHeader>
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool get wantKeepAlive => true;
|
bool get wantKeepAlive => true;
|
||||||
|
|
||||||
|
Widget _buildClientAvatar() {
|
||||||
|
const borderRadius = BorderRadius.all(Radius.circular(15.0));
|
||||||
|
final avatar = client.avatar.trim();
|
||||||
|
if (avatar.startsWith('data:image/')) {
|
||||||
|
final comma = avatar.indexOf(',');
|
||||||
|
if (comma > 0) {
|
||||||
|
try {
|
||||||
|
final bytes = base64Decode(avatar.substring(comma + 1));
|
||||||
|
return ClipRRect(
|
||||||
|
borderRadius: borderRadius,
|
||||||
|
child: Image.memory(
|
||||||
|
bytes,
|
||||||
|
width: 70,
|
||||||
|
height: 70,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
} else if (avatar.startsWith('http://') || avatar.startsWith('https://')) {
|
||||||
|
return ClipRRect(
|
||||||
|
borderRadius: borderRadius,
|
||||||
|
child: Image.network(
|
||||||
|
avatar,
|
||||||
|
width: 70,
|
||||||
|
height: 70,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
errorBuilder: (_, __, ___) => _buildInitialAvatar(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return _buildInitialAvatar();
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildInitialAvatar() {
|
||||||
|
return Container(
|
||||||
|
width: 70,
|
||||||
|
height: 70,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: str2color(client.name),
|
||||||
|
borderRadius: BorderRadius.circular(15.0),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
client.name[0],
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 55,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _PrivilegeBoard extends StatefulWidget {
|
class _PrivilegeBoard extends StatefulWidget {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
@@ -841,13 +842,7 @@ class ClientInfo extends StatelessWidget {
|
|||||||
flex: -1,
|
flex: -1,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(right: 12),
|
padding: const EdgeInsets.only(right: 12),
|
||||||
child: CircleAvatar(
|
child: _buildAvatar(context))),
|
||||||
backgroundColor: str2color(
|
|
||||||
client.name,
|
|
||||||
Theme.of(context).brightness == Brightness.light
|
|
||||||
? 255
|
|
||||||
: 150),
|
|
||||||
child: Text(client.name[0])))),
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@@ -860,6 +855,31 @@ class ClientInfo extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildAvatar(BuildContext context) {
|
||||||
|
final avatar = client.avatar.trim();
|
||||||
|
if (avatar.isNotEmpty) {
|
||||||
|
if (avatar.startsWith('data:image/')) {
|
||||||
|
final comma = avatar.indexOf(',');
|
||||||
|
if (comma > 0) {
|
||||||
|
try {
|
||||||
|
return CircleAvatar(
|
||||||
|
backgroundImage: MemoryImage(base64Decode(avatar.substring(comma + 1))),
|
||||||
|
);
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
} else if (avatar.startsWith('http://') || avatar.startsWith('https://')) {
|
||||||
|
return CircleAvatar(backgroundImage: NetworkImage(avatar));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Show character as before if no avatar
|
||||||
|
return CircleAvatar(
|
||||||
|
backgroundColor: str2color(
|
||||||
|
client.name,
|
||||||
|
Theme.of(context).brightness == Brightness.light ? 255 : 150),
|
||||||
|
child: Text(client.name[0]),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void androidChannelInit() {
|
void androidChannelInit() {
|
||||||
|
|||||||
@@ -820,6 +820,7 @@ class Client {
|
|||||||
bool isTerminal = false;
|
bool isTerminal = false;
|
||||||
String portForward = "";
|
String portForward = "";
|
||||||
String name = "";
|
String name = "";
|
||||||
|
String avatar = "";
|
||||||
String peerId = ""; // peer user's id,show at app
|
String peerId = ""; // peer user's id,show at app
|
||||||
bool keyboard = false;
|
bool keyboard = false;
|
||||||
bool clipboard = false;
|
bool clipboard = false;
|
||||||
@@ -847,6 +848,7 @@ class Client {
|
|||||||
isTerminal = json['is_terminal'] ?? false;
|
isTerminal = json['is_terminal'] ?? false;
|
||||||
portForward = json['port_forward'];
|
portForward = json['port_forward'];
|
||||||
name = json['name'];
|
name = json['name'];
|
||||||
|
avatar = json['avatar'] ?? '';
|
||||||
peerId = json['peer_id'];
|
peerId = json['peer_id'];
|
||||||
keyboard = json['keyboard'];
|
keyboard = json['keyboard'];
|
||||||
clipboard = json['clipboard'];
|
clipboard = json['clipboard'];
|
||||||
@@ -870,6 +872,7 @@ class Client {
|
|||||||
data['is_terminal'] = isTerminal;
|
data['is_terminal'] = isTerminal;
|
||||||
data['port_forward'] = portForward;
|
data['port_forward'] = portForward;
|
||||||
data['name'] = name;
|
data['name'] = name;
|
||||||
|
data['avatar'] = avatar;
|
||||||
data['peer_id'] = peerId;
|
data['peer_id'] = peerId;
|
||||||
data['keyboard'] = keyboard;
|
data['keyboard'] = keyboard;
|
||||||
data['clipboard'] = clipboard;
|
data['clipboard'] = clipboard;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ bool refreshingUser = false;
|
|||||||
class UserModel {
|
class UserModel {
|
||||||
final RxString userName = ''.obs;
|
final RxString userName = ''.obs;
|
||||||
final RxString displayName = ''.obs;
|
final RxString displayName = ''.obs;
|
||||||
|
final RxString avatar = ''.obs;
|
||||||
final RxBool isAdmin = false.obs;
|
final RxBool isAdmin = false.obs;
|
||||||
final RxString networkError = ''.obs;
|
final RxString networkError = ''.obs;
|
||||||
bool get isLogin => userName.isNotEmpty;
|
bool get isLogin => userName.isNotEmpty;
|
||||||
@@ -87,6 +88,7 @@ class UserModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final user = UserPayload.fromJson(data);
|
final user = UserPayload.fromJson(data);
|
||||||
|
user.avatar = _resolveAvatar(user.avatar, url);
|
||||||
_parseAndUpdateUser(user);
|
_parseAndUpdateUser(user);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('Failed to refreshCurrentUser: $e');
|
debugPrint('Failed to refreshCurrentUser: $e');
|
||||||
@@ -114,6 +116,7 @@ class UserModel {
|
|||||||
if (userInfo != null) {
|
if (userInfo != null) {
|
||||||
userName.value = (userInfo['name'] ?? '').toString();
|
userName.value = (userInfo['name'] ?? '').toString();
|
||||||
displayName.value = (userInfo['display_name'] ?? '').toString();
|
displayName.value = (userInfo['display_name'] ?? '').toString();
|
||||||
|
avatar.value = (userInfo['avatar'] ?? '').toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,13 +129,16 @@ class UserModel {
|
|||||||
}
|
}
|
||||||
userName.value = '';
|
userName.value = '';
|
||||||
displayName.value = '';
|
displayName.value = '';
|
||||||
|
avatar.value = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
_parseAndUpdateUser(UserPayload user) {
|
_parseAndUpdateUser(UserPayload user) {
|
||||||
userName.value = user.name;
|
userName.value = user.name;
|
||||||
displayName.value = user.displayName;
|
displayName.value = user.displayName;
|
||||||
|
avatar.value = user.avatar;
|
||||||
isAdmin.value = user.isAdmin;
|
isAdmin.value = user.isAdmin;
|
||||||
bind.mainSetLocalOption(key: 'user_info', value: jsonEncode(user));
|
bind.mainSetLocalOption(key: 'user_info', value: jsonEncode(user));
|
||||||
|
_updateLocalUserInfo();
|
||||||
if (isWeb) {
|
if (isWeb) {
|
||||||
// ugly here, tmp solution
|
// ugly here, tmp solution
|
||||||
bind.mainSetLocalOption(key: 'verifier', value: user.verifier ?? '');
|
bind.mainSetLocalOption(key: 'verifier', value: user.verifier ?? '');
|
||||||
|
|||||||
@@ -2625,6 +2625,19 @@ impl LoginConfigHandler {
|
|||||||
} else {
|
} else {
|
||||||
(my_id, self.id.clone())
|
(my_id, self.id.clone())
|
||||||
};
|
};
|
||||||
|
let mut avatar = get_builtin_option(keys::OPTION_AVATAR);
|
||||||
|
if avatar.is_empty() {
|
||||||
|
avatar = serde_json::from_str::<serde_json::Value>(&LocalConfig::get_option(
|
||||||
|
"user_info",
|
||||||
|
))
|
||||||
|
.ok()
|
||||||
|
.and_then(|x| {
|
||||||
|
x.get("avatar")
|
||||||
|
.and_then(|x| x.as_str())
|
||||||
|
.map(|x| x.trim().to_owned())
|
||||||
|
})
|
||||||
|
.unwrap_or_default();
|
||||||
|
}
|
||||||
let mut display_name = get_builtin_option(keys::OPTION_DISPLAY_NAME);
|
let mut display_name = get_builtin_option(keys::OPTION_DISPLAY_NAME);
|
||||||
if display_name.is_empty() {
|
if display_name.is_empty() {
|
||||||
display_name =
|
display_name =
|
||||||
@@ -2684,6 +2697,7 @@ impl LoginConfigHandler {
|
|||||||
})
|
})
|
||||||
.into(),
|
.into(),
|
||||||
hwid,
|
hwid,
|
||||||
|
avatar,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
match self.conn_type {
|
match self.conn_type {
|
||||||
|
|||||||
@@ -82,6 +82,8 @@ pub struct UserPayload {
|
|||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub display_name: Option<String>,
|
pub display_name: Option<String>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
pub avatar: Option<String>,
|
||||||
|
#[serde(default)]
|
||||||
pub email: Option<String>,
|
pub email: Option<String>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub note: Option<String>,
|
pub note: Option<String>,
|
||||||
@@ -273,6 +275,7 @@ impl OidcSession {
|
|||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"name": auth_body.user.name,
|
"name": auth_body.user.name,
|
||||||
"display_name": auth_body.user.display_name,
|
"display_name": auth_body.user.display_name,
|
||||||
|
"avatar": auth_body.user.avatar,
|
||||||
"status": auth_body.user.status
|
"status": auth_body.user.status
|
||||||
})
|
})
|
||||||
.to_string(),
|
.to_string(),
|
||||||
|
|||||||
@@ -226,6 +226,7 @@ pub enum Data {
|
|||||||
is_terminal: bool,
|
is_terminal: bool,
|
||||||
peer_id: String,
|
peer_id: String,
|
||||||
name: String,
|
name: String,
|
||||||
|
avatar: String,
|
||||||
authorized: bool,
|
authorized: bool,
|
||||||
port_forward: String,
|
port_forward: String,
|
||||||
keyboard: bool,
|
keyboard: bool,
|
||||||
|
|||||||
@@ -1813,6 +1813,7 @@ impl Connection {
|
|||||||
port_forward: self.port_forward_address.clone(),
|
port_forward: self.port_forward_address.clone(),
|
||||||
peer_id,
|
peer_id,
|
||||||
name,
|
name,
|
||||||
|
avatar: self.lr.avatar.clone(),
|
||||||
authorized,
|
authorized,
|
||||||
keyboard: self.keyboard,
|
keyboard: self.keyboard,
|
||||||
clipboard: self.clipboard,
|
clipboard: self.clipboard,
|
||||||
|
|||||||
@@ -57,6 +57,11 @@ div.icon {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
img.icon {
|
||||||
|
size: 96px;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
div.id {
|
div.id {
|
||||||
@ELLIPSIS;
|
@ELLIPSIS;
|
||||||
color: color(green-blue);
|
color: color(green-blue);
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ impl InvokeUiCM for SciterHandler {
|
|||||||
client.port_forward.clone(),
|
client.port_forward.clone(),
|
||||||
client.peer_id.clone(),
|
client.peer_id.clone(),
|
||||||
client.name.clone(),
|
client.name.clone(),
|
||||||
|
client.avatar.clone(),
|
||||||
client.authorized,
|
client.authorized,
|
||||||
client.keyboard,
|
client.keyboard,
|
||||||
client.clipboard,
|
client.clipboard,
|
||||||
|
|||||||
@@ -42,9 +42,11 @@ class Body: Reactor.Component
|
|||||||
return <div .content style="size:*">
|
return <div .content style="size:*">
|
||||||
<div .left-panel>
|
<div .left-panel>
|
||||||
<div .icon-and-id>
|
<div .icon-and-id>
|
||||||
|
{c.avatar ?
|
||||||
|
<img .icon src={c.avatar} /> :
|
||||||
<div .icon style={"background: " + string2RGB(c.name, 1)}>
|
<div .icon style={"background: " + string2RGB(c.name, 1)}>
|
||||||
{c.name[0].toUpperCase()}
|
{c.name[0].toUpperCase()}
|
||||||
</div>
|
</div>}
|
||||||
<div>
|
<div>
|
||||||
<div .id style="font-weight: bold; font-size: 1.2em;">{c.name}</div>
|
<div .id style="font-weight: bold; font-size: 1.2em;">{c.name}</div>
|
||||||
<div .id>({c.peer_id})</div>
|
<div .id>({c.peer_id})</div>
|
||||||
@@ -366,7 +368,7 @@ function bring_to_top(idx=-1) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handler.addConnection = function(id, is_file_transfer, is_view_camera, is_terminal, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file, restart, recording, block_input) {
|
handler.addConnection = function(id, is_file_transfer, is_view_camera, is_terminal, port_forward, peer_id, name, avatar, authorized, keyboard, clipboard, audio, file, restart, recording, block_input) {
|
||||||
stdout.println("new connection #" + id + ": " + peer_id);
|
stdout.println("new connection #" + id + ": " + peer_id);
|
||||||
var conn;
|
var conn;
|
||||||
connections.map(function(c) {
|
connections.map(function(c) {
|
||||||
@@ -385,6 +387,7 @@ handler.addConnection = function(id, is_file_transfer, is_view_camera, is_termin
|
|||||||
conn = {
|
conn = {
|
||||||
id: id, is_file_transfer: is_file_transfer, is_view_camera: is_view_camera, is_terminal: is_terminal, peer_id: peer_id,
|
id: id, is_file_transfer: is_file_transfer, is_view_camera: is_view_camera, is_terminal: is_terminal, peer_id: peer_id,
|
||||||
port_forward: port_forward,
|
port_forward: port_forward,
|
||||||
|
avatar: avatar,
|
||||||
name: name, authorized: authorized, time: new Date(), now: new Date(),
|
name: name, authorized: authorized, time: new Date(), now: new Date(),
|
||||||
keyboard: keyboard, clipboard: clipboard, msgs: [], unreaded: 0,
|
keyboard: keyboard, clipboard: clipboard, msgs: [], unreaded: 0,
|
||||||
audio: audio, file: file, restart: restart, recording: recording,
|
audio: audio, file: file, restart: restart, recording: recording,
|
||||||
|
|||||||
@@ -1451,6 +1451,9 @@ function set_local_user_info(user) {
|
|||||||
if (user.display_name) {
|
if (user.display_name) {
|
||||||
user_info.display_name = user.display_name;
|
user_info.display_name = user.display_name;
|
||||||
}
|
}
|
||||||
|
if (user.avatar) {
|
||||||
|
user_info.avatar = user.avatar;
|
||||||
|
}
|
||||||
if (user.status) {
|
if (user.status) {
|
||||||
user_info.status = user.status;
|
user_info.status = user.status;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -134,6 +134,7 @@ pub struct Client {
|
|||||||
pub is_terminal: bool,
|
pub is_terminal: bool,
|
||||||
pub port_forward: String,
|
pub port_forward: String,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
pub avatar: String,
|
||||||
pub peer_id: String,
|
pub peer_id: String,
|
||||||
pub keyboard: bool,
|
pub keyboard: bool,
|
||||||
pub clipboard: bool,
|
pub clipboard: bool,
|
||||||
@@ -220,6 +221,7 @@ impl<T: InvokeUiCM> ConnectionManager<T> {
|
|||||||
port_forward: String,
|
port_forward: String,
|
||||||
peer_id: String,
|
peer_id: String,
|
||||||
name: String,
|
name: String,
|
||||||
|
avatar: String,
|
||||||
authorized: bool,
|
authorized: bool,
|
||||||
keyboard: bool,
|
keyboard: bool,
|
||||||
clipboard: bool,
|
clipboard: bool,
|
||||||
@@ -240,6 +242,7 @@ impl<T: InvokeUiCM> ConnectionManager<T> {
|
|||||||
is_terminal,
|
is_terminal,
|
||||||
port_forward,
|
port_forward,
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
|
avatar,
|
||||||
peer_id: peer_id.clone(),
|
peer_id: peer_id.clone(),
|
||||||
keyboard,
|
keyboard,
|
||||||
clipboard,
|
clipboard,
|
||||||
@@ -500,9 +503,9 @@ impl<T: InvokeUiCM> IpcTaskRunner<T> {
|
|||||||
}
|
}
|
||||||
Ok(Some(data)) => {
|
Ok(Some(data)) => {
|
||||||
match data {
|
match data {
|
||||||
Data::Login{id, is_file_transfer, is_view_camera, is_terminal, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file, file_transfer_enabled: _file_transfer_enabled, restart, recording, block_input, from_switch} => {
|
Data::Login{id, is_file_transfer, is_view_camera, is_terminal, port_forward, peer_id, name, avatar, authorized, keyboard, clipboard, audio, file, file_transfer_enabled: _file_transfer_enabled, restart, recording, block_input, from_switch} => {
|
||||||
log::debug!("conn_id: {}", id);
|
log::debug!("conn_id: {}", id);
|
||||||
self.cm.add_connection(id, is_file_transfer, is_view_camera, is_terminal, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file, restart, recording, block_input, from_switch, self.tx.clone());
|
self.cm.add_connection(id, is_file_transfer, is_view_camera, is_terminal, port_forward, peer_id, name, avatar, authorized, keyboard, clipboard, audio, file, restart, recording, block_input, from_switch, self.tx.clone());
|
||||||
self.conn_id = id;
|
self.conn_id = id;
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
{
|
{
|
||||||
@@ -823,6 +826,7 @@ pub async fn start_listen<T: InvokeUiCM>(
|
|||||||
port_forward,
|
port_forward,
|
||||||
peer_id,
|
peer_id,
|
||||||
name,
|
name,
|
||||||
|
avatar,
|
||||||
authorized,
|
authorized,
|
||||||
keyboard,
|
keyboard,
|
||||||
clipboard,
|
clipboard,
|
||||||
@@ -843,6 +847,7 @@ pub async fn start_listen<T: InvokeUiCM>(
|
|||||||
port_forward,
|
port_forward,
|
||||||
peer_id,
|
peer_id,
|
||||||
name,
|
name,
|
||||||
|
avatar,
|
||||||
authorized,
|
authorized,
|
||||||
keyboard,
|
keyboard,
|
||||||
clipboard,
|
clipboard,
|
||||||
|
|||||||
@@ -245,7 +245,39 @@ pub fn get_builtin_option(key: &str) -> String {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_local_option(key: String, value: String) {
|
pub fn set_local_option(key: String, value: String) {
|
||||||
LocalConfig::set_option(key.clone(), value.clone());
|
let value = normalize_local_option_value(&key, value);
|
||||||
|
LocalConfig::set_option(key.clone(), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn normalize_local_option_value(key: &str, value: String) -> String {
|
||||||
|
if key != "user_info" || value.is_empty() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
let Ok(mut v) = serde_json::from_str::<serde_json::Value>(&value) else {
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
let Some(obj) = v.as_object_mut() else {
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
let Some(avatar) = obj
|
||||||
|
.get("avatar")
|
||||||
|
.and_then(|x| x.as_str())
|
||||||
|
.map(|x| x.trim().to_owned())
|
||||||
|
else {
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
if !avatar.starts_with('/') {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
let api_server = get_api_server();
|
||||||
|
if api_server.is_empty() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
obj.insert(
|
||||||
|
"avatar".to_owned(),
|
||||||
|
serde_json::Value::String(format!("{}{}", api_server.trim_end_matches('/'), avatar)),
|
||||||
|
);
|
||||||
|
serde_json::to_string(&v).unwrap_or(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))]
|
#[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))]
|
||||||
|
|||||||
Reference in New Issue
Block a user