Merge pull request #1354 from 21pages/style

keep text scale factor && peer style change
This commit is contained in:
RustDesk 2022-08-25 10:28:25 +08:00 committed by GitHub
commit 1f457dec41
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 462 additions and 380 deletions

Binary file not shown.

View File

@ -41,15 +41,18 @@ late final iconRestart = MemoryImage(Uint8List.fromList(base64Decode(
'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAB7BAAAewQHDaVRTAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAbhJREFUWIXVlrFqFGEUhb+7UYxaWCQKlrKKxaZSQVGDJih2tj6MD2DnMwiWvoAIRnENIpZiYxEro6IooiS7SPwsMgNLkk3mjmYmnmb45/73nMNwz/x/qH3gMu2gH6rAU+Blw+Lngau4jpmGxVF7qp1iPWjaQKnZ2WnXbuP/NqAeUPc3ZkA9XDwvqc+BVWCgPlJ7tRwUKThZce819b46VH+pfXVRXVO/q2cSul3VOgZUl0ejq86r39TXI8mqZKDuDEwCw3IREQvAbWAGmMsQZQ0sAl3gHPB1Q+0e8BuYzRDuy2yOiFVgaUxtRf0ETGc4syk4rc6PqU0Cx9j8Zf6dAeAK8Fi9sUXtFjABvEgxJlNwRP2svlNPjbw/q35U36oTFbnyMSwabxb/gB/qA3VBHagrauV7RW0DRfP1IvMlXqkXkhz1DYyQTKtHa/Z2VVMx3IiI+PI3/bCHjuOpFrSnAMpL6QfgTcMGesDx0kBr2BMzsNyi/vtQu8CJlgwsRbZDnWP90NkKaxHxJMOXMqAeAn5u0ydwMCKGY+qbkB3C2W3EKWoXk5zVoHbUZ+6Mh7tl4G4F8RJ3qvL+AfV3r5Vdpj70AAAAAElFTkSuQmCC'))); 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAB7BAAAewQHDaVRTAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAbhJREFUWIXVlrFqFGEUhb+7UYxaWCQKlrKKxaZSQVGDJih2tj6MD2DnMwiWvoAIRnENIpZiYxEro6IooiS7SPwsMgNLkk3mjmYmnmb45/73nMNwz/x/qH3gMu2gH6rAU+Blw+Lngau4jpmGxVF7qp1iPWjaQKnZ2WnXbuP/NqAeUPc3ZkA9XDwvqc+BVWCgPlJ7tRwUKThZce819b46VH+pfXVRXVO/q2cSul3VOgZUl0ejq86r39TXI8mqZKDuDEwCw3IREQvAbWAGmMsQZQ0sAl3gHPB1Q+0e8BuYzRDuy2yOiFVgaUxtRf0ETGc4syk4rc6PqU0Cx9j8Zf6dAeAK8Fi9sUXtFjABvEgxJlNwRP2svlNPjbw/q35U36oTFbnyMSwabxb/gB/qA3VBHagrauV7RW0DRfP1IvMlXqkXkhz1DYyQTKtHa/Z2VVMx3IiI+PI3/bCHjuOpFrSnAMpL6QfgTcMGesDx0kBr2BMzsNyi/vtQu8CJlgwsRbZDnWP90NkKaxHxJMOXMqAeAn5u0ydwMCKGY+qbkB3C2W3EKWoXk5zVoHbUZ+6Mh7tl4G4F8RJ3qvL+AfV3r5Vdpj70AAAAAElFTkSuQmCC')));
class IconFont { class IconFont {
static const _family = 'iconfont'; static const _family1 = 'Tabbar';
static const _family2 = 'PeerSearchbar';
IconFont._(); IconFont._();
static const IconData max = IconData(0xe606, fontFamily: _family); static const IconData max = IconData(0xe606, fontFamily: _family1);
static const IconData restore = IconData(0xe607, fontFamily: _family); static const IconData restore = IconData(0xe607, fontFamily: _family1);
static const IconData close = IconData(0xe668, fontFamily: _family); static const IconData close = IconData(0xe668, fontFamily: _family1);
static const IconData min = IconData(0xe609, fontFamily: _family); static const IconData min = IconData(0xe609, fontFamily: _family1);
static const IconData add = IconData(0xe664, fontFamily: _family); static const IconData add = IconData(0xe664, fontFamily: _family1);
static const IconData menu = IconData(0xe628, fontFamily: _family); static const IconData menu = IconData(0xe628, fontFamily: _family1);
static const IconData search = IconData(0xe6a4, fontFamily: _family2);
static const IconData round_close = IconData(0xe6ed, fontFamily: _family2);
} }
class ColorThemeExtension extends ThemeExtension<ColorThemeExtension> { class ColorThemeExtension extends ThemeExtension<ColorThemeExtension> {

View File

@ -63,70 +63,43 @@ class _ConnectionPageState extends State<ConnectionPage> {
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[ children: <Widget>[
getUpdateUI(),
Row(
children: [
getSearchBarUI(context),
],
).marginOnly(top: 22, left: 22),
SizedBox(height: 12),
Divider(
thickness: 1,
indent: 22,
endIndent: 22,
),
Expanded( Expanded(
// TODO: move all tab info into _PeerTabbedPage child: Column(
child: _PeerTabbedPage( children: [
tabs: [ getUpdateUI(),
translate('Recent Sessions'), Row(
translate('Favorites'), children: [
translate('Discovered'), getSearchBarUI(context),
translate('Address Book') ],
], ).marginOnly(top: 22),
children: [ SizedBox(height: 12),
RecentPeerWidget(), Divider(),
FavoritePeerWidget(), Expanded(
DiscoveredPeerWidget(), child: _PeerTabbedPage(
// AddressBookPeerWidget(), tabs: [
// FutureBuilder<Widget>( translate('Recent Sessions'),
// future: getPeers(rType: RemoteType.recently), translate('Favorites'),
// builder: (context, snapshot) { translate('Discovered'),
// if (snapshot.hasData) { translate('Address Book')
// return snapshot.data!; ],
// } else { children: [
// return Offstage(); RecentPeerWidget(),
// } FavoritePeerWidget(),
// }), DiscoveredPeerWidget(),
// FutureBuilder<Widget>( FutureBuilder<Widget>(
// future: getPeers(rType: RemoteType.favorite), future: buildAddressBook(context),
// builder: (context, snapshot) { builder: (context, snapshot) {
// if (snapshot.hasData) { if (snapshot.hasData) {
// return snapshot.data!; return snapshot.data!;
// } else { } else {
// return Offstage(); return Offstage();
// } }
// }), }),
// FutureBuilder<Widget>( ],
// future: getPeers(rType: RemoteType.discovered), )),
// builder: (context, snapshot) { ],
// if (snapshot.hasData) { ).marginSymmetric(horizontal: 22),
// return snapshot.data!; ),
// } else {
// return Offstage();
// }
// }),
FutureBuilder<Widget>(
future: buildAddressBook(context),
builder: (context, snapshot) {
if (snapshot.hasData) {
return snapshot.data!;
} else {
return Offstage();
}
}),
],
).marginSymmetric(horizontal: 6)),
Divider(), Divider(),
SizedBox(height: 50, child: Obx(() => buildStatus())) SizedBox(height: 50, child: Obx(() => buildStatus()))
.paddingSymmetric(horizontal: 12.0) .paddingSymmetric(horizontal: 12.0)
@ -186,9 +159,14 @@ class _ConnectionPageState extends State<ConnectionPage> {
RxBool ftPressed = false.obs; RxBool ftPressed = false.obs;
RxBool connHover = false.obs; RxBool connHover = false.obs;
RxBool connPressed = false.obs; RxBool connPressed = false.obs;
RxBool inputFocused = false.obs;
FocusNode focusNode = FocusNode();
focusNode.addListener(() {
inputFocused.value = focusNode.hasFocus;
});
var w = Container( var w = Container(
width: 320 + 20 * 2, width: 320 + 20 * 2,
padding: EdgeInsets.only(left: 20, right: 20, bottom: 22, top: 30), padding: EdgeInsets.fromLTRB(20, 24, 20, 22),
decoration: BoxDecoration( decoration: BoxDecoration(
color: MyTheme.color(context).bg, color: MyTheme.color(context).bg,
borderRadius: const BorderRadius.all(Radius.circular(13)), borderRadius: const BorderRadius.all(Radius.circular(13)),
@ -197,36 +175,45 @@ class _ConnectionPageState extends State<ConnectionPage> {
child: Column( child: Column(
children: [ children: [
Row( Row(
children: <Widget>[ children: [
Text(
translate('Control Remote Desktop'),
style: TextStyle(fontSize: 19, height: 1),
),
],
).marginOnly(bottom: 15),
Row(
children: [
Expanded( Expanded(
child: Container( child: TextField(
child: TextField( autocorrect: false,
autocorrect: false, enableSuggestions: false,
enableSuggestions: false, keyboardType: TextInputType.visiblePassword,
keyboardType: TextInputType.visiblePassword, style: TextStyle(
style: TextStyle( fontFamily: 'WorkSans',
fontFamily: 'WorkSans', fontSize: 22,
fontSize: 22, height: 1,
),
decoration: InputDecoration(
labelText: translate('Control Remote Desktop'),
border:
OutlineInputBorder(borderRadius: BorderRadius.zero),
helperStyle: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
labelStyle: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 26,
letterSpacing: 0.2,
),
),
controller: _idController,
onSubmitted: (s) {
onConnect();
},
), ),
decoration: InputDecoration(
hintText: translate('Enter Remote ID'),
hintStyle: TextStyle(
color: MyTheme.color(context).placeholder),
border: OutlineInputBorder(
borderRadius: BorderRadius.zero,
borderSide: BorderSide(
color: MyTheme.color(context).placeholder!)),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.zero,
borderSide:
BorderSide(color: MyTheme.button, width: 3),
),
isDense: true,
contentPadding:
EdgeInsets.symmetric(horizontal: 10, vertical: 12)),
controller: _idController,
onSubmitted: (s) {
onConnect();
},
), ),
), ),
], ],
@ -963,67 +950,57 @@ class _PeerTabbedPage extends StatefulWidget {
class _PeerTabbedPageState extends State<_PeerTabbedPage> class _PeerTabbedPageState extends State<_PeerTabbedPage>
with SingleTickerProviderStateMixin { with SingleTickerProviderStateMixin {
late TabController _tabController; late PageController _pageController = PageController();
RxInt _tabIndex = 0.obs; RxInt _tabIndex = 0.obs;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_tabController =
TabController(vsync: this, length: super.widget.tabs.length);
_tabController.addListener(_handleTabSelection);
} }
// hard code for now // hard code for now
void _handleTabSelection() { void _handleTabSelection(int index) {
if (_tabController.indexIsChanging) { // reset search text
// reset search text peerSearchText.value = "";
peerSearchText.value = ""; peerSearchTextController.clear();
peerSearchTextController.clear(); _tabIndex.value = index;
_tabIndex.value = _tabController.index; _pageController.jumpToPage(index);
switch (_tabController.index) { switch (index) {
case 0: case 0:
bind.mainLoadRecentPeers(); bind.mainLoadRecentPeers();
break; break;
case 1: case 1:
bind.mainLoadFavPeers(); bind.mainLoadFavPeers();
break; break;
case 2: case 2:
bind.mainDiscover(); bind.mainDiscover();
break; break;
case 3: case 3:
break; break;
}
} }
} }
@override @override
void dispose() { void dispose() {
_tabController.dispose(); _pageController.dispose();
super.dispose(); super.dispose();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// return DefaultTabController(
// length: 4,
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// _createTabBar(),
// _createTabBarView(),
// ],
// ));
return Column( return Column(
textBaseline: TextBaseline.ideographic,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Row( Container(
children: [ height: 28,
Expanded(child: _createTabBar(context)), child: Row(
_createSearchBar(context), children: [
_createPeerViewTypeSwitch(context), Expanded(child: _createTabBar(context)),
], _createSearchBar(context),
_createPeerViewTypeSwitch(context),
],
),
), ),
_createTabBarView(), _createTabBarView(),
], ],
@ -1031,70 +1008,121 @@ class _PeerTabbedPageState extends State<_PeerTabbedPage>
} }
Widget _createTabBar(BuildContext context) { Widget _createTabBar(BuildContext context) {
return TabBar( return ListView(
isScrollable: true, scrollDirection: Axis.horizontal,
indicatorSize: TabBarIndicatorSize.label, shrinkWrap: true,
indicatorColor: Colors.transparent, children: super.widget.tabs.asMap().entries.map((t) {
indicatorWeight: 0.1, return Obx(() => GestureDetector(
controller: _tabController, child: Container(
labelPadding: EdgeInsets.zero, padding: EdgeInsets.symmetric(horizontal: 8),
padding: EdgeInsets.only(left: 16), decoration: BoxDecoration(
tabs: super.widget.tabs.asMap().entries.map((t) { color: _tabIndex.value == t.key
return Obx(() => Container( ? MyTheme.color(context).bg
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 6), : null,
decoration: BoxDecoration( borderRadius: BorderRadius.circular(2),
color: ),
_tabIndex.value == t.key ? MyTheme.color(context).bg : null, child: Align(
borderRadius: BorderRadius.circular(2), alignment: Alignment.center,
), child: Text(
child: Text( t.value,
t.value, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
height: 1, height: 1,
color: _tabIndex.value == t.key fontSize: 14,
? MyTheme.color(context).text color: _tabIndex.value == t.key
: MyTheme.color(context).lightText), ? MyTheme.color(context).text
))); : MyTheme.color(context).lightText),
),
)),
onTap: () => _handleTabSelection(t.key),
));
}).toList()); }).toList());
} }
Widget _createTabBarView() { Widget _createTabBarView() {
return Expanded( return Expanded(
child: TabBarView( child: PageView(
controller: _tabController, children: super.widget.children) controller: _pageController, children: super.widget.children)
.paddingSymmetric(horizontal: 12.0, vertical: 4.0)); .marginSymmetric(vertical: 12));
} }
_createSearchBar(BuildContext context) { _createSearchBar(BuildContext context) {
RxBool focused = false.obs;
FocusNode focusNode = FocusNode();
focusNode.addListener(() => focused.value = focusNode.hasFocus);
RxBool rowHover = false.obs;
RxBool clearHover = false.obs;
return Container( return Container(
width: 175, width: 120,
height: 30, height: 25,
margin: EdgeInsets.only(right: 16), margin: EdgeInsets.only(right: 13),
decoration: BoxDecoration(color: Colors.white), decoration: BoxDecoration(color: MyTheme.color(context).bg),
child: Obx( child: Obx(() => Row(
() => TextField( children: [
controller: peerSearchTextController, Expanded(
onChanged: (searchText) { child: MouseRegion(
peerSearchText.value = searchText; onEnter: (_) => rowHover.value = true,
}, onExit: (_) => rowHover.value = false,
decoration: InputDecoration( child: Row(
prefixIcon: Icon( children: [
Icons.search, Icon(
size: 20, IconFont.search,
), size: 16,
contentPadding: EdgeInsets.zero, color: MyTheme.color(context).placeholder,
hintText: translate("Search ID"), ).marginSymmetric(horizontal: 4),
hintStyle: TextStyle(fontSize: 14), Expanded(
border: OutlineInputBorder(), child: TextField(
isDense: true, controller: peerSearchTextController,
), onChanged: (searchText) {
), peerSearchText.value = searchText;
), },
focusNode: focusNode,
textAlign: TextAlign.start,
maxLines: 1,
cursorColor: MyTheme.color(context).lightText,
cursorHeight: 18,
cursorWidth: 1,
style: TextStyle(fontSize: 14),
decoration: InputDecoration(
contentPadding: EdgeInsets.symmetric(vertical: 6),
hintText:
focused.value ? null : translate("Search ID"),
hintStyle: TextStyle(
fontSize: 14,
color: MyTheme.color(context).placeholder),
border: InputBorder.none,
isDense: true,
),
),
),
],
),
),
),
Offstage(
offstage: !(peerSearchText.value.isNotEmpty &&
(rowHover.value || clearHover.value)),
child: InkWell(
onHover: (value) => clearHover.value = value,
child: Icon(
IconFont.round_close,
size: 16,
color: clearHover.value
? MyTheme.color(context).text
: MyTheme.color(context).placeholder,
).marginSymmetric(horizontal: 4),
onTap: () {
peerSearchTextController.clear();
peerSearchText.value = "";
}),
)
],
)),
); );
} }
_createPeerViewTypeSwitch(BuildContext context) { _createPeerViewTypeSwitch(BuildContext context) {
final activeDeco = BoxDecoration(color: Colors.white); final activeDeco = BoxDecoration(color: MyTheme.color(context).bg);
return Row( return Row(
children: [ children: [
Obx( Obx(
@ -1108,8 +1136,10 @@ class _PeerTabbedPageState extends State<_PeerTabbedPage>
}, },
child: Icon( child: Icon(
Icons.grid_view_rounded, Icons.grid_view_rounded,
size: 20, size: 18,
color: Colors.black54, color: peerCardUiType.value == PeerUiType.grid
? MyTheme.color(context).text
: MyTheme.color(context).lightText,
)), )),
), ),
), ),
@ -1124,12 +1154,14 @@ class _PeerTabbedPageState extends State<_PeerTabbedPage>
}, },
child: Icon( child: Icon(
Icons.list, Icons.list,
size: 24, size: 18,
color: Colors.black54, color: peerCardUiType.value == PeerUiType.list
? MyTheme.color(context).text
: MyTheme.color(context).lightText,
)), )),
), ),
), ),
], ],
).paddingOnly(right: 16.0); );
} }
} }

View File

@ -107,9 +107,10 @@ class _DesktopHomePageState extends State<DesktopHomePage>
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Container( Container(
height: 15, height: 25,
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
translate("ID"), translate("ID"),
@ -133,7 +134,7 @@ class _DesktopHomePageState extends State<DesktopHomePage>
readOnly: true, readOnly: true,
decoration: InputDecoration( decoration: InputDecoration(
border: InputBorder.none, border: InputBorder.none,
contentPadding: EdgeInsets.only(bottom: 8), contentPadding: EdgeInsets.only(bottom: 18),
), ),
style: TextStyle( style: TextStyle(
fontSize: 22, fontSize: 22,
@ -239,26 +240,17 @@ class _DesktopHomePageState extends State<DesktopHomePage>
} }
}, },
child: Obx( child: Obx(
() => Container( () => CircleAvatar(
decoration: BoxDecoration( radius: 12,
// borderRadius: BorderRadius.circular(10), backgroundColor: hover.value
shape: BoxShape.circle, ? MyTheme.color(context).grayBg!
boxShadow: [ : MyTheme.color(context).bg!,
BoxShadow( child: Icon(
color: hover.value Icons.more_vert_outlined,
? MyTheme.color(context).grayBg! size: 20,
: MyTheme.color(context).bg!, color: hover.value
spreadRadius: 2) ? MyTheme.color(context).text
], : MyTheme.color(context).lightText,
),
child: Center(
child: Icon(
Icons.more_vert_outlined,
size: 20,
color: hover.value
? MyTheme.color(context).text
: MyTheme.color(context).lightText,
),
), ),
), ),
), ),

View File

@ -26,11 +26,10 @@ const double _kContentFontSize = 15;
const Color _accentColor = MyTheme.accent; const Color _accentColor = MyTheme.accent;
class _TabInfo { class _TabInfo {
late final int index;
late final String label; late final String label;
late final IconData unselected; late final IconData unselected;
late final IconData selected; late final IconData selected;
_TabInfo(this.index, this.label, this.unselected, this.selected); _TabInfo(this.label, this.unselected, this.selected);
} }
class DesktopSettingPage extends StatefulWidget { class DesktopSettingPage extends StatefulWidget {
@ -43,17 +42,15 @@ class DesktopSettingPage extends StatefulWidget {
class _DesktopSettingPageState extends State<DesktopSettingPage> class _DesktopSettingPageState extends State<DesktopSettingPage>
with TickerProviderStateMixin, AutomaticKeepAliveClientMixin { with TickerProviderStateMixin, AutomaticKeepAliveClientMixin {
final List<_TabInfo> _setting_tabs = <_TabInfo>[ final List<_TabInfo> _setting_tabs = <_TabInfo>[
_TabInfo( _TabInfo('User Interface', Icons.language_outlined, Icons.language_sharp),
0, 'User Interface', Icons.language_outlined, Icons.language_sharp), _TabInfo('Security', Icons.enhanced_encryption_outlined,
_TabInfo(1, 'Security', Icons.enhanced_encryption_outlined,
Icons.enhanced_encryption_sharp), Icons.enhanced_encryption_sharp),
_TabInfo(2, 'Display', Icons.desktop_windows_outlined, _TabInfo(
Icons.desktop_windows_sharp), 'Display', Icons.desktop_windows_outlined, Icons.desktop_windows_sharp),
_TabInfo(3, 'Audio', Icons.volume_up_outlined, Icons.volume_up_sharp), _TabInfo('Audio', Icons.volume_up_outlined, Icons.volume_up_sharp),
_TabInfo(4, 'Connection', Icons.link_outlined, Icons.link_sharp), _TabInfo('Connection', Icons.link_outlined, Icons.link_sharp),
_TabInfo('About RustDesk', Icons.info_outline, Icons.info_sharp)
]; ];
final _TabInfo _about_tab =
_TabInfo(5, 'About RustDesk', Icons.info_outline, Icons.info_sharp);
late PageController controller; late PageController controller;
RxInt _selectedIndex = 0.obs; RxInt _selectedIndex = 0.obs;
@ -80,10 +77,6 @@ class _DesktopSettingPageState extends State<DesktopSettingPage>
children: [ children: [
_header(), _header(),
Flexible(child: _listView(tabs: _setting_tabs)), Flexible(child: _listView(tabs: _setting_tabs)),
_listItem(tab: _about_tab),
SizedBox(
height: 120,
)
], ],
), ),
), ),
@ -131,22 +124,26 @@ class _DesktopSettingPageState extends State<DesktopSettingPage>
Widget _listView({required List<_TabInfo> tabs}) { Widget _listView({required List<_TabInfo> tabs}) {
return ListView( return ListView(
children: tabs.map((tab) => _listItem(tab: tab)).toList(), children: tabs
.asMap()
.entries
.map((tab) => _listItem(tab: tab.value, index: tab.key))
.toList(),
); );
} }
Widget _listItem({required _TabInfo tab}) { Widget _listItem({required _TabInfo tab, required int index}) {
return Obx(() { return Obx(() {
bool selected = tab.index == _selectedIndex.value; bool selected = index == _selectedIndex.value;
return Container( return Container(
width: _kTabWidth, width: _kTabWidth,
height: _kTabHeight, height: _kTabHeight,
child: InkWell( child: InkWell(
onTap: () { onTap: () {
if (_selectedIndex.value != tab.index) { if (_selectedIndex.value != index) {
controller.jumpToPage(tab.index); controller.jumpToPage(index);
} }
_selectedIndex.value = tab.index; _selectedIndex.value = index;
}, },
child: Row(children: [ child: Row(children: [
Container( Container(
@ -665,7 +662,7 @@ class _AboutState extends State<_About> {
final version = data['version'].toString(); final version = data['version'].toString();
final linkStyle = TextStyle(decoration: TextDecoration.underline); final linkStyle = TextStyle(decoration: TextDecoration.underline);
return ListView(children: [ return ListView(children: [
_Card(title: "About Rustdesk", children: [ _Card(title: "About RustDesk", children: [
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [

View File

@ -100,10 +100,10 @@ class _PeerWidgetState extends State<_PeerWidget> with WindowListener {
offstage: super.widget._offstageFunc(peer), offstage: super.widget._offstageFunc(peer),
child: Obx( child: Obx(
() => Container( () => Container(
width: 225, width: 220,
height: peerCardUiType.value == PeerUiType.grid height: peerCardUiType.value == PeerUiType.grid
? 150 ? 140
: 50, : 42,
child: VisibilityDetector( child: VisibilityDetector(
key: Key('${peer.id}'), key: Key('${peer.id}'),
onVisibilityChanged: (info) { onVisibilityChanged: (info) {

View File

@ -36,29 +36,31 @@ class _PeerCard extends StatefulWidget {
class _PeerCardState extends State<_PeerCard> class _PeerCardState extends State<_PeerCard>
with AutomaticKeepAliveClientMixin { with AutomaticKeepAliveClientMixin {
var _menuPos; var _menuPos;
final double _cardRadis = 20;
final double _borderWidth = 2;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
super.build(context); super.build(context);
final peer = super.widget.peer; final peer = super.widget.peer;
var deco = Rx<BoxDecoration?>(BoxDecoration( var deco = Rx<BoxDecoration?>(BoxDecoration(
border: Border.all(color: Colors.transparent, width: 1.0), border: Border.all(color: Colors.transparent, width: _borderWidth),
borderRadius: peerCardUiType.value == PeerUiType.grid borderRadius: peerCardUiType.value == PeerUiType.grid
? BorderRadius.circular(20) ? BorderRadius.circular(_cardRadis)
: null)); : null));
return MouseRegion( return MouseRegion(
onEnter: (evt) { onEnter: (evt) {
deco.value = BoxDecoration( deco.value = BoxDecoration(
border: Border.all(color: Colors.blue, width: 1.0), border: Border.all(color: MyTheme.button, width: _borderWidth),
borderRadius: peerCardUiType.value == PeerUiType.grid borderRadius: peerCardUiType.value == PeerUiType.grid
? BorderRadius.circular(20) ? BorderRadius.circular(_cardRadis)
: null); : null);
}, },
onExit: (evt) { onExit: (evt) {
deco.value = BoxDecoration( deco.value = BoxDecoration(
border: Border.all(color: Colors.transparent, width: 1.0), border: Border.all(color: Colors.transparent, width: _borderWidth),
borderRadius: peerCardUiType.value == PeerUiType.grid borderRadius: peerCardUiType.value == PeerUiType.grid
? BorderRadius.circular(20) ? BorderRadius.circular(_cardRadis)
: null); : null);
}, },
child: GestureDetector( child: GestureDetector(
@ -71,25 +73,25 @@ class _PeerCardState extends State<_PeerCard>
Widget _buildPeerTile( Widget _buildPeerTile(
BuildContext context, Peer peer, Rx<BoxDecoration?> deco) { BuildContext context, Peer peer, Rx<BoxDecoration?> deco) {
final greyStyle = TextStyle(fontSize: 12, color: Colors.grey); final greyStyle =
TextStyle(fontSize: 12, color: MyTheme.color(context).lighterText);
RxBool iconHover = false.obs;
return Obx( return Obx(
() => Container( () => Container(
decoration: deco.value, foregroundDecoration: deco.value,
child: Row( child: Row(
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
children: [ children: [
Container( Container(
height: 50,
width: 50,
decoration: BoxDecoration( decoration: BoxDecoration(
color: str2color('${peer.id}${peer.platform}', 0x7f), color: str2color('${peer.id}${peer.platform}', 0x7f),
), ),
alignment: Alignment.center, alignment: Alignment.center,
child: _getPlatformImage('${peer.platform}').paddingAll(8.0), child: _getPlatformImage('${peer.platform}', 30).paddingAll(6),
), ),
Expanded( Expanded(
child: Container( child: Container(
decoration: BoxDecoration(color: Colors.white), decoration: BoxDecoration(color: MyTheme.color(context).bg),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
@ -98,17 +100,17 @@ class _PeerCardState extends State<_PeerCard>
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [ children: [
Row(children: [ Row(children: [
Text(
'${peer.id}',
style: TextStyle(fontWeight: FontWeight.w400),
),
Padding( Padding(
padding: EdgeInsets.fromLTRB(4, 4, 8, 4), padding: EdgeInsets.fromLTRB(0, 4, 4, 4),
child: CircleAvatar( child: CircleAvatar(
radius: 5, radius: 5,
backgroundColor: peer.online backgroundColor: peer.online
? Colors.green ? Colors.green
: Colors.yellow)), : Colors.yellow)),
Text(
'${peer.id}',
style: TextStyle(fontWeight: FontWeight.w400),
),
]), ]),
Align( Align(
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
@ -122,6 +124,7 @@ class _PeerCardState extends State<_PeerCard>
: snapshot.data!; : snapshot.data!;
return Tooltip( return Tooltip(
message: name, message: name,
waitDuration: Duration(seconds: 1),
child: Text( child: Text(
name, name,
style: greyStyle, style: greyStyle,
@ -145,17 +148,31 @@ class _PeerCardState extends State<_PeerCard>
), ),
), ),
InkWell( InkWell(
child: Icon(Icons.more_vert), child: CircleAvatar(
onTapDown: (e) { radius: 12,
final x = e.globalPosition.dx; backgroundColor: iconHover.value
final y = e.globalPosition.dy; ? MyTheme.color(context).grayBg!
_menuPos = RelativeRect.fromLTRB(x, y, x, y); : MyTheme.color(context).bg!,
}, child: Icon(
onTap: () { Icons.more_vert,
_showPeerMenu(context, peer.id); size: 18,
}), color: iconHover.value
? MyTheme.color(context).text
: MyTheme.color(context).lightText,
),
),
onTapDown: (e) {
final x = e.globalPosition.dx;
final y = e.globalPosition.dy;
_menuPos = RelativeRect.fromLTRB(x, y, x, y);
},
onTap: () {
_showPeerMenu(context, peer.id);
},
onHover: (value) => iconHover.value = value,
),
], ],
).paddingSymmetric(horizontal: 8.0), ).paddingSymmetric(horizontal: 4.0),
), ),
) )
], ],
@ -166,105 +183,121 @@ class _PeerCardState extends State<_PeerCard>
Widget _buildPeerCard( Widget _buildPeerCard(
BuildContext context, Peer peer, Rx<BoxDecoration?> deco) { BuildContext context, Peer peer, Rx<BoxDecoration?> deco) {
RxBool iconHover = false.obs;
return Card( return Card(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), color: Colors.transparent,
elevation: 0,
margin: EdgeInsets.zero,
child: Obx( child: Obx(
() => Container( () => Container(
decoration: deco.value, foregroundDecoration: deco.value,
child: Column( child: ClipRRect(
mainAxisSize: MainAxisSize.min, borderRadius: BorderRadius.circular(_cardRadis - _borderWidth),
mainAxisAlignment: MainAxisAlignment.center, child: Column(
children: [ mainAxisSize: MainAxisSize.min,
Expanded( mainAxisAlignment: MainAxisAlignment.center,
child: Container( children: [
decoration: BoxDecoration( Expanded(
child: Container(
color: str2color('${peer.id}${peer.platform}', 0x7f), color: str2color('${peer.id}${peer.platform}', 0x7f),
borderRadius: BorderRadius.only( child: Row(
topLeft: Radius.circular(20), children: [
topRight: Radius.circular(20), Expanded(
), child: Column(
), crossAxisAlignment: CrossAxisAlignment.center,
child: Row( children: [
children: [ Container(
Expanded( padding: const EdgeInsets.all(6),
child: Column( child:
crossAxisAlignment: CrossAxisAlignment.center, _getPlatformImage('${peer.platform}', 60),
children: [ ),
Container( Row(
padding: const EdgeInsets.all(6), children: [
child: _getPlatformImage('${peer.platform}'), Expanded(
), child: FutureBuilder<String>(
Row( future: bind.mainGetPeerOption(
children: [ id: peer.id, key: 'alias'),
Expanded( builder: (_, snapshot) {
child: FutureBuilder<String>( if (snapshot.hasData) {
future: bind.mainGetPeerOption( final name = snapshot.data!.isEmpty
id: peer.id, key: 'alias'), ? '${peer.username}@${peer.hostname}'
builder: (_, snapshot) { : snapshot.data!;
if (snapshot.hasData) { return Tooltip(
final name = snapshot.data!.isEmpty message: name,
? '${peer.username}@${peer.hostname}' waitDuration: Duration(seconds: 1),
: snapshot.data!; child: Text(
return Tooltip( name,
message: name, style: TextStyle(
child: Text( color: Colors.white70,
name, fontSize: 12),
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
),
);
} else {
// alias has not arrived
return Center(
child: Text(
'${peer.username}@${peer.hostname}',
style: TextStyle( style: TextStyle(
color: Colors.white70, color: Colors.white70,
fontSize: 12), fontSize: 12),
textAlign: TextAlign.center, textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ));
); }
} else { },
// alias has not arrived ),
return Center(
child: Text(
'${peer.username}@${peer.hostname}',
style: TextStyle(
color: Colors.white70,
fontSize: 12),
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
));
}
},
), ),
), ],
], ),
), ],
], ).paddingAll(4.0),
).paddingAll(4.0), ),
), ],
], ),
), ),
), ),
), Container(
Row( color: MyTheme.color(context).bg,
mainAxisAlignment: MainAxisAlignment.spaceBetween, child: Row(
children: [ mainAxisAlignment: MainAxisAlignment.spaceBetween,
Row(children: [ children: [
Padding( Row(children: [
padding: EdgeInsets.fromLTRB(0, 4, 8, 4), Padding(
child: CircleAvatar( padding: EdgeInsets.fromLTRB(0, 4, 8, 4),
radius: 5, child: CircleAvatar(
backgroundColor: radius: 5,
peer.online ? Colors.green : Colors.yellow)), backgroundColor: peer.online
Text('${peer.id}') ? Colors.green
]), : Colors.yellow)),
InkWell( Text('${peer.id}')
child: Icon(Icons.more_vert), ]),
onTapDown: (e) { InkWell(
final x = e.globalPosition.dx; child: CircleAvatar(
final y = e.globalPosition.dy; radius: 12,
_menuPos = RelativeRect.fromLTRB(x, y, x, y); backgroundColor: iconHover.value
}, ? MyTheme.color(context).grayBg!
onTap: () { : MyTheme.color(context).bg!,
_showPeerMenu(context, peer.id); child: Icon(Icons.more_vert,
}), size: 18,
], color: iconHover.value
).paddingSymmetric(vertical: 8.0, horizontal: 12.0) ? MyTheme.color(context).text
], : MyTheme.color(context).lightText)),
onTapDown: (e) {
final x = e.globalPosition.dx;
final y = e.globalPosition.dy;
_menuPos = RelativeRect.fromLTRB(x, y, x, y);
},
onTap: () {
_showPeerMenu(context, peer.id);
},
onHover: (value) => iconHover.value = value),
],
).paddingSymmetric(vertical: 8.0, horizontal: 12.0),
)
],
),
), ),
), ),
), ),
@ -365,12 +398,12 @@ class _PeerCardState extends State<_PeerCard>
} }
/// Get the image for the current [platform]. /// Get the image for the current [platform].
Widget _getPlatformImage(String platform) { Widget _getPlatformImage(String platform, double size) {
platform = platform.toLowerCase(); platform = platform.toLowerCase();
if (platform == 'mac os') if (platform == 'mac os')
platform = 'mac'; platform = 'mac';
else if (platform != 'linux' && platform != 'android') platform = 'win'; else if (platform != 'linux' && platform != 'android') platform = 'win';
return Image.asset('assets/$platform.png', height: 50); return Image.asset('assets/$platform.png', height: size, width: size);
} }
void _abEditTag(String id) { void _abEditTag(String id) {

View File

@ -514,8 +514,10 @@ class ActionIcon extends StatelessWidget {
RxBool hover = false.obs; RxBool hover = false.obs;
return Obx(() => Tooltip( return Obx(() => Tooltip(
message: translate(message), message: translate(message),
waitDuration: Duration(seconds: 1),
child: InkWell( child: InkWell(
hoverColor: is_close ? Colors.red : theme.hoverColor, hoverColor:
is_close ? Color.fromARGB(255, 196, 43, 28) : theme.hoverColor,
onHover: (value) => hover.value = value, onHover: (value) => hover.value = value,
child: Container( child: Container(
height: _kTabBarHeight - 1, height: _kTabBarHeight - 1,

View File

@ -112,12 +112,14 @@ void runRemoteScreen(Map<String, dynamic> argument) async {
navigatorObservers: [ navigatorObservers: [
// FirebaseAnalyticsObserver(analytics: analytics), // FirebaseAnalyticsObserver(analytics: analytics),
], ],
builder: _keepScaleBuilder(),
)); ));
} }
void runFileTransferScreen(Map<String, dynamic> argument) async { void runFileTransferScreen(Map<String, dynamic> argument) async {
await initEnv(kAppTypeDesktopFileTransfer); await initEnv(kAppTypeDesktopFileTransfer);
runApp(GetMaterialApp( runApp(
GetMaterialApp(
navigatorKey: globalKey, navigatorKey: globalKey,
debugShowCheckedModeBanner: false, debugShowCheckedModeBanner: false,
title: 'RustDesk - File Transfer', title: 'RustDesk - File Transfer',
@ -125,7 +127,10 @@ void runFileTransferScreen(Map<String, dynamic> argument) async {
home: DesktopFileTransferScreen(params: argument), home: DesktopFileTransferScreen(params: argument),
navigatorObservers: [ navigatorObservers: [
// FirebaseAnalyticsObserver(analytics: analytics), // FirebaseAnalyticsObserver(analytics: analytics),
])); ],
builder: _keepScaleBuilder(),
),
);
} }
void runConnectionManagerScreen() async { void runConnectionManagerScreen() async {
@ -142,7 +147,8 @@ void runConnectionManagerScreen() async {
runApp(GetMaterialApp( runApp(GetMaterialApp(
debugShowCheckedModeBanner: false, debugShowCheckedModeBanner: false,
theme: getCurrentTheme(), theme: getCurrentTheme(),
home: DesktopServerPage())); home: DesktopServerPage(),
builder: _keepScaleBuilder()));
} }
WindowOptions getHiddenTitleBarWindowOptions(Size size) { WindowOptions getHiddenTitleBarWindowOptions(Size size) {
@ -171,23 +177,35 @@ class App extends StatelessWidget {
ChangeNotifierProvider.value(value: gFFI.userModel), ChangeNotifierProvider.value(value: gFFI.userModel),
], ],
child: GetMaterialApp( child: GetMaterialApp(
navigatorKey: globalKey, navigatorKey: globalKey,
debugShowCheckedModeBanner: false, debugShowCheckedModeBanner: false,
title: 'RustDesk', title: 'RustDesk',
theme: getCurrentTheme(), theme: getCurrentTheme(),
home: isDesktop home: isDesktop
? DesktopTabPage() ? DesktopTabPage()
: !isAndroid : !isAndroid
? WebHomePage() ? WebHomePage()
: HomePage(), : HomePage(),
navigatorObservers: [ navigatorObservers: [
// FirebaseAnalyticsObserver(analytics: analytics), // FirebaseAnalyticsObserver(analytics: analytics),
], ],
builder: isAndroid builder: isAndroid
? (_, child) => AccessibilityListener( ? (_, child) => AccessibilityListener(
child: child, child: child,
) )
: null), : _keepScaleBuilder(),
),
); );
} }
} }
_keepScaleBuilder() {
return (BuildContext context, Widget? child) {
return MediaQuery(
data: MediaQuery.of(context).copyWith(
textScaleFactor: 1.0,
),
child: child ?? Container(),
);
};
}

View File

@ -107,9 +107,14 @@ flutter:
- family: GestureIcons - family: GestureIcons
fonts: fonts:
- asset: assets/gestures.ttf - asset: assets/gestures.ttf
- family: IconFont - family: Tabbar
fonts: fonts:
- asset: assets/tabbar.ttf - asset: assets/tabbar.ttf
- family: PeerSearchbar
fonts:
- asset: assets/peer_searchbar.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.