Merge pull request #1354 from 21pages/style
keep text scale factor && peer style change
This commit is contained in:
commit
1f457dec41
BIN
flutter/assets/peer_searchbar.ttf
Normal file
BIN
flutter/assets/peer_searchbar.ttf
Normal file
Binary file not shown.
@ -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')));
|
||||
|
||||
class IconFont {
|
||||
static const _family = 'iconfont';
|
||||
static const _family1 = 'Tabbar';
|
||||
static const _family2 = 'PeerSearchbar';
|
||||
IconFont._();
|
||||
|
||||
static const IconData max = IconData(0xe606, fontFamily: _family);
|
||||
static const IconData restore = IconData(0xe607, fontFamily: _family);
|
||||
static const IconData close = IconData(0xe668, fontFamily: _family);
|
||||
static const IconData min = IconData(0xe609, fontFamily: _family);
|
||||
static const IconData add = IconData(0xe664, fontFamily: _family);
|
||||
static const IconData menu = IconData(0xe628, fontFamily: _family);
|
||||
static const IconData max = IconData(0xe606, fontFamily: _family1);
|
||||
static const IconData restore = IconData(0xe607, fontFamily: _family1);
|
||||
static const IconData close = IconData(0xe668, fontFamily: _family1);
|
||||
static const IconData min = IconData(0xe609, fontFamily: _family1);
|
||||
static const IconData add = IconData(0xe664, fontFamily: _family1);
|
||||
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> {
|
||||
|
@ -63,70 +63,43 @@ class _ConnectionPageState extends State<ConnectionPage> {
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
getUpdateUI(),
|
||||
Row(
|
||||
children: [
|
||||
getSearchBarUI(context),
|
||||
],
|
||||
).marginOnly(top: 22, left: 22),
|
||||
SizedBox(height: 12),
|
||||
Divider(
|
||||
thickness: 1,
|
||||
indent: 22,
|
||||
endIndent: 22,
|
||||
),
|
||||
Expanded(
|
||||
// TODO: move all tab info into _PeerTabbedPage
|
||||
child: _PeerTabbedPage(
|
||||
tabs: [
|
||||
translate('Recent Sessions'),
|
||||
translate('Favorites'),
|
||||
translate('Discovered'),
|
||||
translate('Address Book')
|
||||
],
|
||||
children: [
|
||||
RecentPeerWidget(),
|
||||
FavoritePeerWidget(),
|
||||
DiscoveredPeerWidget(),
|
||||
// AddressBookPeerWidget(),
|
||||
// FutureBuilder<Widget>(
|
||||
// future: getPeers(rType: RemoteType.recently),
|
||||
// builder: (context, snapshot) {
|
||||
// if (snapshot.hasData) {
|
||||
// return snapshot.data!;
|
||||
// } else {
|
||||
// return Offstage();
|
||||
// }
|
||||
// }),
|
||||
// FutureBuilder<Widget>(
|
||||
// future: getPeers(rType: RemoteType.favorite),
|
||||
// builder: (context, snapshot) {
|
||||
// if (snapshot.hasData) {
|
||||
// return snapshot.data!;
|
||||
// } else {
|
||||
// return Offstage();
|
||||
// }
|
||||
// }),
|
||||
// FutureBuilder<Widget>(
|
||||
// future: getPeers(rType: RemoteType.discovered),
|
||||
// builder: (context, snapshot) {
|
||||
// if (snapshot.hasData) {
|
||||
// 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)),
|
||||
child: Column(
|
||||
children: [
|
||||
getUpdateUI(),
|
||||
Row(
|
||||
children: [
|
||||
getSearchBarUI(context),
|
||||
],
|
||||
).marginOnly(top: 22),
|
||||
SizedBox(height: 12),
|
||||
Divider(),
|
||||
Expanded(
|
||||
child: _PeerTabbedPage(
|
||||
tabs: [
|
||||
translate('Recent Sessions'),
|
||||
translate('Favorites'),
|
||||
translate('Discovered'),
|
||||
translate('Address Book')
|
||||
],
|
||||
children: [
|
||||
RecentPeerWidget(),
|
||||
FavoritePeerWidget(),
|
||||
DiscoveredPeerWidget(),
|
||||
FutureBuilder<Widget>(
|
||||
future: buildAddressBook(context),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
return snapshot.data!;
|
||||
} else {
|
||||
return Offstage();
|
||||
}
|
||||
}),
|
||||
],
|
||||
)),
|
||||
],
|
||||
).marginSymmetric(horizontal: 22),
|
||||
),
|
||||
Divider(),
|
||||
SizedBox(height: 50, child: Obx(() => buildStatus()))
|
||||
.paddingSymmetric(horizontal: 12.0)
|
||||
@ -186,9 +159,14 @@ class _ConnectionPageState extends State<ConnectionPage> {
|
||||
RxBool ftPressed = false.obs;
|
||||
RxBool connHover = false.obs;
|
||||
RxBool connPressed = false.obs;
|
||||
RxBool inputFocused = false.obs;
|
||||
FocusNode focusNode = FocusNode();
|
||||
focusNode.addListener(() {
|
||||
inputFocused.value = focusNode.hasFocus;
|
||||
});
|
||||
var w = Container(
|
||||
width: 320 + 20 * 2,
|
||||
padding: EdgeInsets.only(left: 20, right: 20, bottom: 22, top: 30),
|
||||
padding: EdgeInsets.fromLTRB(20, 24, 20, 22),
|
||||
decoration: BoxDecoration(
|
||||
color: MyTheme.color(context).bg,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(13)),
|
||||
@ -197,36 +175,45 @@ class _ConnectionPageState extends State<ConnectionPage> {
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
children: <Widget>[
|
||||
children: [
|
||||
Text(
|
||||
translate('Control Remote Desktop'),
|
||||
style: TextStyle(fontSize: 19, height: 1),
|
||||
),
|
||||
],
|
||||
).marginOnly(bottom: 15),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
child: TextField(
|
||||
autocorrect: false,
|
||||
enableSuggestions: false,
|
||||
keyboardType: TextInputType.visiblePassword,
|
||||
style: TextStyle(
|
||||
fontFamily: 'WorkSans',
|
||||
fontSize: 22,
|
||||
),
|
||||
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();
|
||||
},
|
||||
child: TextField(
|
||||
autocorrect: false,
|
||||
enableSuggestions: false,
|
||||
keyboardType: TextInputType.visiblePassword,
|
||||
style: TextStyle(
|
||||
fontFamily: 'WorkSans',
|
||||
fontSize: 22,
|
||||
height: 1,
|
||||
),
|
||||
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>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late TabController _tabController;
|
||||
late PageController _pageController = PageController();
|
||||
RxInt _tabIndex = 0.obs;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_tabController =
|
||||
TabController(vsync: this, length: super.widget.tabs.length);
|
||||
_tabController.addListener(_handleTabSelection);
|
||||
}
|
||||
|
||||
// hard code for now
|
||||
void _handleTabSelection() {
|
||||
if (_tabController.indexIsChanging) {
|
||||
// reset search text
|
||||
peerSearchText.value = "";
|
||||
peerSearchTextController.clear();
|
||||
_tabIndex.value = _tabController.index;
|
||||
switch (_tabController.index) {
|
||||
case 0:
|
||||
bind.mainLoadRecentPeers();
|
||||
break;
|
||||
case 1:
|
||||
bind.mainLoadFavPeers();
|
||||
break;
|
||||
case 2:
|
||||
bind.mainDiscover();
|
||||
break;
|
||||
case 3:
|
||||
break;
|
||||
}
|
||||
void _handleTabSelection(int index) {
|
||||
// reset search text
|
||||
peerSearchText.value = "";
|
||||
peerSearchTextController.clear();
|
||||
_tabIndex.value = index;
|
||||
_pageController.jumpToPage(index);
|
||||
switch (index) {
|
||||
case 0:
|
||||
bind.mainLoadRecentPeers();
|
||||
break;
|
||||
case 1:
|
||||
bind.mainLoadFavPeers();
|
||||
break;
|
||||
case 2:
|
||||
bind.mainDiscover();
|
||||
break;
|
||||
case 3:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_tabController.dispose();
|
||||
_pageController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// return DefaultTabController(
|
||||
// length: 4,
|
||||
// child: Column(
|
||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// children: [
|
||||
// _createTabBar(),
|
||||
// _createTabBarView(),
|
||||
// ],
|
||||
// ));
|
||||
|
||||
return Column(
|
||||
textBaseline: TextBaseline.ideographic,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(child: _createTabBar(context)),
|
||||
_createSearchBar(context),
|
||||
_createPeerViewTypeSwitch(context),
|
||||
],
|
||||
Container(
|
||||
height: 28,
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(child: _createTabBar(context)),
|
||||
_createSearchBar(context),
|
||||
_createPeerViewTypeSwitch(context),
|
||||
],
|
||||
),
|
||||
),
|
||||
_createTabBarView(),
|
||||
],
|
||||
@ -1031,70 +1008,121 @@ class _PeerTabbedPageState extends State<_PeerTabbedPage>
|
||||
}
|
||||
|
||||
Widget _createTabBar(BuildContext context) {
|
||||
return TabBar(
|
||||
isScrollable: true,
|
||||
indicatorSize: TabBarIndicatorSize.label,
|
||||
indicatorColor: Colors.transparent,
|
||||
indicatorWeight: 0.1,
|
||||
controller: _tabController,
|
||||
labelPadding: EdgeInsets.zero,
|
||||
padding: EdgeInsets.only(left: 16),
|
||||
tabs: super.widget.tabs.asMap().entries.map((t) {
|
||||
return Obx(() => Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
color:
|
||||
_tabIndex.value == t.key ? MyTheme.color(context).bg : null,
|
||||
borderRadius: BorderRadius.circular(2),
|
||||
),
|
||||
child: Text(
|
||||
t.value,
|
||||
style: TextStyle(
|
||||
height: 1,
|
||||
color: _tabIndex.value == t.key
|
||||
? MyTheme.color(context).text
|
||||
: MyTheme.color(context).lightText),
|
||||
)));
|
||||
return ListView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
shrinkWrap: true,
|
||||
children: super.widget.tabs.asMap().entries.map((t) {
|
||||
return Obx(() => GestureDetector(
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 8),
|
||||
decoration: BoxDecoration(
|
||||
color: _tabIndex.value == t.key
|
||||
? MyTheme.color(context).bg
|
||||
: null,
|
||||
borderRadius: BorderRadius.circular(2),
|
||||
),
|
||||
child: Align(
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
t.value,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
height: 1,
|
||||
fontSize: 14,
|
||||
color: _tabIndex.value == t.key
|
||||
? MyTheme.color(context).text
|
||||
: MyTheme.color(context).lightText),
|
||||
),
|
||||
)),
|
||||
onTap: () => _handleTabSelection(t.key),
|
||||
));
|
||||
}).toList());
|
||||
}
|
||||
|
||||
Widget _createTabBarView() {
|
||||
return Expanded(
|
||||
child: TabBarView(
|
||||
controller: _tabController, children: super.widget.children)
|
||||
.paddingSymmetric(horizontal: 12.0, vertical: 4.0));
|
||||
child: PageView(
|
||||
controller: _pageController, children: super.widget.children)
|
||||
.marginSymmetric(vertical: 12));
|
||||
}
|
||||
|
||||
_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(
|
||||
width: 175,
|
||||
height: 30,
|
||||
margin: EdgeInsets.only(right: 16),
|
||||
decoration: BoxDecoration(color: Colors.white),
|
||||
child: Obx(
|
||||
() => TextField(
|
||||
controller: peerSearchTextController,
|
||||
onChanged: (searchText) {
|
||||
peerSearchText.value = searchText;
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
prefixIcon: Icon(
|
||||
Icons.search,
|
||||
size: 20,
|
||||
),
|
||||
contentPadding: EdgeInsets.zero,
|
||||
hintText: translate("Search ID"),
|
||||
hintStyle: TextStyle(fontSize: 14),
|
||||
border: OutlineInputBorder(),
|
||||
isDense: true,
|
||||
),
|
||||
),
|
||||
),
|
||||
width: 120,
|
||||
height: 25,
|
||||
margin: EdgeInsets.only(right: 13),
|
||||
decoration: BoxDecoration(color: MyTheme.color(context).bg),
|
||||
child: Obx(() => Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: MouseRegion(
|
||||
onEnter: (_) => rowHover.value = true,
|
||||
onExit: (_) => rowHover.value = false,
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
IconFont.search,
|
||||
size: 16,
|
||||
color: MyTheme.color(context).placeholder,
|
||||
).marginSymmetric(horizontal: 4),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
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) {
|
||||
final activeDeco = BoxDecoration(color: Colors.white);
|
||||
final activeDeco = BoxDecoration(color: MyTheme.color(context).bg);
|
||||
return Row(
|
||||
children: [
|
||||
Obx(
|
||||
@ -1108,8 +1136,10 @@ class _PeerTabbedPageState extends State<_PeerTabbedPage>
|
||||
},
|
||||
child: Icon(
|
||||
Icons.grid_view_rounded,
|
||||
size: 20,
|
||||
color: Colors.black54,
|
||||
size: 18,
|
||||
color: peerCardUiType.value == PeerUiType.grid
|
||||
? MyTheme.color(context).text
|
||||
: MyTheme.color(context).lightText,
|
||||
)),
|
||||
),
|
||||
),
|
||||
@ -1124,12 +1154,14 @@ class _PeerTabbedPageState extends State<_PeerTabbedPage>
|
||||
},
|
||||
child: Icon(
|
||||
Icons.list,
|
||||
size: 24,
|
||||
color: Colors.black54,
|
||||
size: 18,
|
||||
color: peerCardUiType.value == PeerUiType.list
|
||||
? MyTheme.color(context).text
|
||||
: MyTheme.color(context).lightText,
|
||||
)),
|
||||
),
|
||||
),
|
||||
],
|
||||
).paddingOnly(right: 16.0);
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -107,9 +107,10 @@ class _DesktopHomePageState extends State<DesktopHomePage>
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
height: 15,
|
||||
height: 25,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
translate("ID"),
|
||||
@ -133,7 +134,7 @@ class _DesktopHomePageState extends State<DesktopHomePage>
|
||||
readOnly: true,
|
||||
decoration: InputDecoration(
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.only(bottom: 8),
|
||||
contentPadding: EdgeInsets.only(bottom: 18),
|
||||
),
|
||||
style: TextStyle(
|
||||
fontSize: 22,
|
||||
@ -239,26 +240,17 @@ class _DesktopHomePageState extends State<DesktopHomePage>
|
||||
}
|
||||
},
|
||||
child: Obx(
|
||||
() => Container(
|
||||
decoration: BoxDecoration(
|
||||
// borderRadius: BorderRadius.circular(10),
|
||||
shape: BoxShape.circle,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: hover.value
|
||||
? MyTheme.color(context).grayBg!
|
||||
: MyTheme.color(context).bg!,
|
||||
spreadRadius: 2)
|
||||
],
|
||||
),
|
||||
child: Center(
|
||||
child: Icon(
|
||||
Icons.more_vert_outlined,
|
||||
size: 20,
|
||||
color: hover.value
|
||||
? MyTheme.color(context).text
|
||||
: MyTheme.color(context).lightText,
|
||||
),
|
||||
() => CircleAvatar(
|
||||
radius: 12,
|
||||
backgroundColor: hover.value
|
||||
? MyTheme.color(context).grayBg!
|
||||
: MyTheme.color(context).bg!,
|
||||
child: Icon(
|
||||
Icons.more_vert_outlined,
|
||||
size: 20,
|
||||
color: hover.value
|
||||
? MyTheme.color(context).text
|
||||
: MyTheme.color(context).lightText,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -26,11 +26,10 @@ const double _kContentFontSize = 15;
|
||||
const Color _accentColor = MyTheme.accent;
|
||||
|
||||
class _TabInfo {
|
||||
late final int index;
|
||||
late final String label;
|
||||
late final IconData unselected;
|
||||
late final IconData selected;
|
||||
_TabInfo(this.index, this.label, this.unselected, this.selected);
|
||||
_TabInfo(this.label, this.unselected, this.selected);
|
||||
}
|
||||
|
||||
class DesktopSettingPage extends StatefulWidget {
|
||||
@ -43,17 +42,15 @@ class DesktopSettingPage extends StatefulWidget {
|
||||
class _DesktopSettingPageState extends State<DesktopSettingPage>
|
||||
with TickerProviderStateMixin, AutomaticKeepAliveClientMixin {
|
||||
final List<_TabInfo> _setting_tabs = <_TabInfo>[
|
||||
_TabInfo(
|
||||
0, 'User Interface', Icons.language_outlined, Icons.language_sharp),
|
||||
_TabInfo(1, 'Security', Icons.enhanced_encryption_outlined,
|
||||
_TabInfo('User Interface', Icons.language_outlined, Icons.language_sharp),
|
||||
_TabInfo('Security', Icons.enhanced_encryption_outlined,
|
||||
Icons.enhanced_encryption_sharp),
|
||||
_TabInfo(2, 'Display', Icons.desktop_windows_outlined,
|
||||
Icons.desktop_windows_sharp),
|
||||
_TabInfo(3, 'Audio', Icons.volume_up_outlined, Icons.volume_up_sharp),
|
||||
_TabInfo(4, 'Connection', Icons.link_outlined, Icons.link_sharp),
|
||||
_TabInfo(
|
||||
'Display', Icons.desktop_windows_outlined, Icons.desktop_windows_sharp),
|
||||
_TabInfo('Audio', Icons.volume_up_outlined, Icons.volume_up_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;
|
||||
RxInt _selectedIndex = 0.obs;
|
||||
@ -80,10 +77,6 @@ class _DesktopSettingPageState extends State<DesktopSettingPage>
|
||||
children: [
|
||||
_header(),
|
||||
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}) {
|
||||
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(() {
|
||||
bool selected = tab.index == _selectedIndex.value;
|
||||
bool selected = index == _selectedIndex.value;
|
||||
return Container(
|
||||
width: _kTabWidth,
|
||||
height: _kTabHeight,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
if (_selectedIndex.value != tab.index) {
|
||||
controller.jumpToPage(tab.index);
|
||||
if (_selectedIndex.value != index) {
|
||||
controller.jumpToPage(index);
|
||||
}
|
||||
_selectedIndex.value = tab.index;
|
||||
_selectedIndex.value = index;
|
||||
},
|
||||
child: Row(children: [
|
||||
Container(
|
||||
@ -665,7 +662,7 @@ class _AboutState extends State<_About> {
|
||||
final version = data['version'].toString();
|
||||
final linkStyle = TextStyle(decoration: TextDecoration.underline);
|
||||
return ListView(children: [
|
||||
_Card(title: "About Rustdesk", children: [
|
||||
_Card(title: "About RustDesk", children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
|
@ -100,10 +100,10 @@ class _PeerWidgetState extends State<_PeerWidget> with WindowListener {
|
||||
offstage: super.widget._offstageFunc(peer),
|
||||
child: Obx(
|
||||
() => Container(
|
||||
width: 225,
|
||||
width: 220,
|
||||
height: peerCardUiType.value == PeerUiType.grid
|
||||
? 150
|
||||
: 50,
|
||||
? 140
|
||||
: 42,
|
||||
child: VisibilityDetector(
|
||||
key: Key('${peer.id}'),
|
||||
onVisibilityChanged: (info) {
|
||||
|
@ -36,29 +36,31 @@ class _PeerCard extends StatefulWidget {
|
||||
class _PeerCardState extends State<_PeerCard>
|
||||
with AutomaticKeepAliveClientMixin {
|
||||
var _menuPos;
|
||||
final double _cardRadis = 20;
|
||||
final double _borderWidth = 2;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
super.build(context);
|
||||
final peer = super.widget.peer;
|
||||
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.circular(20)
|
||||
? BorderRadius.circular(_cardRadis)
|
||||
: null));
|
||||
return MouseRegion(
|
||||
onEnter: (evt) {
|
||||
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.circular(20)
|
||||
? BorderRadius.circular(_cardRadis)
|
||||
: null);
|
||||
},
|
||||
onExit: (evt) {
|
||||
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.circular(20)
|
||||
? BorderRadius.circular(_cardRadis)
|
||||
: null);
|
||||
},
|
||||
child: GestureDetector(
|
||||
@ -71,25 +73,25 @@ class _PeerCardState extends State<_PeerCard>
|
||||
|
||||
Widget _buildPeerTile(
|
||||
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(
|
||||
() => Container(
|
||||
decoration: deco.value,
|
||||
foregroundDecoration: deco.value,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
Container(
|
||||
height: 50,
|
||||
width: 50,
|
||||
decoration: BoxDecoration(
|
||||
color: str2color('${peer.id}${peer.platform}', 0x7f),
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
child: _getPlatformImage('${peer.platform}').paddingAll(8.0),
|
||||
child: _getPlatformImage('${peer.platform}', 30).paddingAll(6),
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(color: Colors.white),
|
||||
decoration: BoxDecoration(color: MyTheme.color(context).bg),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
@ -98,17 +100,17 @@ class _PeerCardState extends State<_PeerCard>
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Row(children: [
|
||||
Text(
|
||||
'${peer.id}',
|
||||
style: TextStyle(fontWeight: FontWeight.w400),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.fromLTRB(4, 4, 8, 4),
|
||||
padding: EdgeInsets.fromLTRB(0, 4, 4, 4),
|
||||
child: CircleAvatar(
|
||||
radius: 5,
|
||||
backgroundColor: peer.online
|
||||
? Colors.green
|
||||
: Colors.yellow)),
|
||||
Text(
|
||||
'${peer.id}',
|
||||
style: TextStyle(fontWeight: FontWeight.w400),
|
||||
),
|
||||
]),
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
@ -122,6 +124,7 @@ class _PeerCardState extends State<_PeerCard>
|
||||
: snapshot.data!;
|
||||
return Tooltip(
|
||||
message: name,
|
||||
waitDuration: Duration(seconds: 1),
|
||||
child: Text(
|
||||
name,
|
||||
style: greyStyle,
|
||||
@ -145,17 +148,31 @@ class _PeerCardState extends State<_PeerCard>
|
||||
),
|
||||
),
|
||||
InkWell(
|
||||
child: Icon(Icons.more_vert),
|
||||
onTapDown: (e) {
|
||||
final x = e.globalPosition.dx;
|
||||
final y = e.globalPosition.dy;
|
||||
_menuPos = RelativeRect.fromLTRB(x, y, x, y);
|
||||
},
|
||||
onTap: () {
|
||||
_showPeerMenu(context, peer.id);
|
||||
}),
|
||||
child: CircleAvatar(
|
||||
radius: 12,
|
||||
backgroundColor: iconHover.value
|
||||
? MyTheme.color(context).grayBg!
|
||||
: MyTheme.color(context).bg!,
|
||||
child: Icon(
|
||||
Icons.more_vert,
|
||||
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(
|
||||
BuildContext context, Peer peer, Rx<BoxDecoration?> deco) {
|
||||
RxBool iconHover = false.obs;
|
||||
return Card(
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
|
||||
color: Colors.transparent,
|
||||
elevation: 0,
|
||||
margin: EdgeInsets.zero,
|
||||
child: Obx(
|
||||
() => Container(
|
||||
decoration: deco.value,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
foregroundDecoration: deco.value,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(_cardRadis - _borderWidth),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
color: str2color('${peer.id}${peer.platform}', 0x7f),
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(20),
|
||||
topRight: Radius.circular(20),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(6),
|
||||
child: _getPlatformImage('${peer.platform}'),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: FutureBuilder<String>(
|
||||
future: bind.mainGetPeerOption(
|
||||
id: peer.id, key: 'alias'),
|
||||
builder: (_, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
final name = snapshot.data!.isEmpty
|
||||
? '${peer.username}@${peer.hostname}'
|
||||
: snapshot.data!;
|
||||
return Tooltip(
|
||||
message: name,
|
||||
child: Text(
|
||||
name,
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(6),
|
||||
child:
|
||||
_getPlatformImage('${peer.platform}', 60),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: FutureBuilder<String>(
|
||||
future: bind.mainGetPeerOption(
|
||||
id: peer.id, key: 'alias'),
|
||||
builder: (_, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
final name = snapshot.data!.isEmpty
|
||||
? '${peer.username}@${peer.hostname}'
|
||||
: snapshot.data!;
|
||||
return Tooltip(
|
||||
message: name,
|
||||
waitDuration: Duration(seconds: 1),
|
||||
child: Text(
|
||||
name,
|
||||
style: TextStyle(
|
||||
color: Colors.white70,
|
||||
fontSize: 12),
|
||||
textAlign: TextAlign.center,
|
||||
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,
|
||||
),
|
||||
);
|
||||
} 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),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.fromLTRB(0, 4, 8, 4),
|
||||
child: CircleAvatar(
|
||||
radius: 5,
|
||||
backgroundColor:
|
||||
peer.online ? Colors.green : Colors.yellow)),
|
||||
Text('${peer.id}')
|
||||
]),
|
||||
InkWell(
|
||||
child: Icon(Icons.more_vert),
|
||||
onTapDown: (e) {
|
||||
final x = e.globalPosition.dx;
|
||||
final y = e.globalPosition.dy;
|
||||
_menuPos = RelativeRect.fromLTRB(x, y, x, y);
|
||||
},
|
||||
onTap: () {
|
||||
_showPeerMenu(context, peer.id);
|
||||
}),
|
||||
],
|
||||
).paddingSymmetric(vertical: 8.0, horizontal: 12.0)
|
||||
],
|
||||
Container(
|
||||
color: MyTheme.color(context).bg,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.fromLTRB(0, 4, 8, 4),
|
||||
child: CircleAvatar(
|
||||
radius: 5,
|
||||
backgroundColor: peer.online
|
||||
? Colors.green
|
||||
: Colors.yellow)),
|
||||
Text('${peer.id}')
|
||||
]),
|
||||
InkWell(
|
||||
child: CircleAvatar(
|
||||
radius: 12,
|
||||
backgroundColor: iconHover.value
|
||||
? MyTheme.color(context).grayBg!
|
||||
: MyTheme.color(context).bg!,
|
||||
child: Icon(Icons.more_vert,
|
||||
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(vertical: 8.0, horizontal: 12.0),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -365,12 +398,12 @@ class _PeerCardState extends State<_PeerCard>
|
||||
}
|
||||
|
||||
/// Get the image for the current [platform].
|
||||
Widget _getPlatformImage(String platform) {
|
||||
Widget _getPlatformImage(String platform, double size) {
|
||||
platform = platform.toLowerCase();
|
||||
if (platform == 'mac os')
|
||||
platform = 'mac';
|
||||
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) {
|
||||
|
@ -514,8 +514,10 @@ class ActionIcon extends StatelessWidget {
|
||||
RxBool hover = false.obs;
|
||||
return Obx(() => Tooltip(
|
||||
message: translate(message),
|
||||
waitDuration: Duration(seconds: 1),
|
||||
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,
|
||||
child: Container(
|
||||
height: _kTabBarHeight - 1,
|
||||
|
@ -112,12 +112,14 @@ void runRemoteScreen(Map<String, dynamic> argument) async {
|
||||
navigatorObservers: [
|
||||
// FirebaseAnalyticsObserver(analytics: analytics),
|
||||
],
|
||||
builder: _keepScaleBuilder(),
|
||||
));
|
||||
}
|
||||
|
||||
void runFileTransferScreen(Map<String, dynamic> argument) async {
|
||||
await initEnv(kAppTypeDesktopFileTransfer);
|
||||
runApp(GetMaterialApp(
|
||||
runApp(
|
||||
GetMaterialApp(
|
||||
navigatorKey: globalKey,
|
||||
debugShowCheckedModeBanner: false,
|
||||
title: 'RustDesk - File Transfer',
|
||||
@ -125,7 +127,10 @@ void runFileTransferScreen(Map<String, dynamic> argument) async {
|
||||
home: DesktopFileTransferScreen(params: argument),
|
||||
navigatorObservers: [
|
||||
// FirebaseAnalyticsObserver(analytics: analytics),
|
||||
]));
|
||||
],
|
||||
builder: _keepScaleBuilder(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void runConnectionManagerScreen() async {
|
||||
@ -142,7 +147,8 @@ void runConnectionManagerScreen() async {
|
||||
runApp(GetMaterialApp(
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: getCurrentTheme(),
|
||||
home: DesktopServerPage()));
|
||||
home: DesktopServerPage(),
|
||||
builder: _keepScaleBuilder()));
|
||||
}
|
||||
|
||||
WindowOptions getHiddenTitleBarWindowOptions(Size size) {
|
||||
@ -171,23 +177,35 @@ class App extends StatelessWidget {
|
||||
ChangeNotifierProvider.value(value: gFFI.userModel),
|
||||
],
|
||||
child: GetMaterialApp(
|
||||
navigatorKey: globalKey,
|
||||
debugShowCheckedModeBanner: false,
|
||||
title: 'RustDesk',
|
||||
theme: getCurrentTheme(),
|
||||
home: isDesktop
|
||||
? DesktopTabPage()
|
||||
: !isAndroid
|
||||
? WebHomePage()
|
||||
: HomePage(),
|
||||
navigatorObservers: [
|
||||
// FirebaseAnalyticsObserver(analytics: analytics),
|
||||
],
|
||||
builder: isAndroid
|
||||
? (_, child) => AccessibilityListener(
|
||||
child: child,
|
||||
)
|
||||
: null),
|
||||
navigatorKey: globalKey,
|
||||
debugShowCheckedModeBanner: false,
|
||||
title: 'RustDesk',
|
||||
theme: getCurrentTheme(),
|
||||
home: isDesktop
|
||||
? DesktopTabPage()
|
||||
: !isAndroid
|
||||
? WebHomePage()
|
||||
: HomePage(),
|
||||
navigatorObservers: [
|
||||
// FirebaseAnalyticsObserver(analytics: analytics),
|
||||
],
|
||||
builder: isAndroid
|
||||
? (_, child) => AccessibilityListener(
|
||||
child: child,
|
||||
)
|
||||
: _keepScaleBuilder(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
_keepScaleBuilder() {
|
||||
return (BuildContext context, Widget? child) {
|
||||
return MediaQuery(
|
||||
data: MediaQuery.of(context).copyWith(
|
||||
textScaleFactor: 1.0,
|
||||
),
|
||||
child: child ?? Container(),
|
||||
);
|
||||
};
|
||||
}
|
||||
|
@ -107,9 +107,14 @@ flutter:
|
||||
- family: GestureIcons
|
||||
fonts:
|
||||
- asset: assets/gestures.ttf
|
||||
- family: IconFont
|
||||
- family: Tabbar
|
||||
fonts:
|
||||
- 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
|
||||
# https://flutter.dev/assets-and-images/#resolution-aware.
|
||||
|
Loading…
x
Reference in New Issue
Block a user