diff --git a/flutter/lib/common/widgets/chat_page.dart b/flutter/lib/common/widgets/chat_page.dart index 9460f4f41..54805c94a 100644 --- a/flutter/lib/common/widgets/chat_page.dart +++ b/flutter/lib/common/widgets/chat_page.dart @@ -1,7 +1,9 @@ import 'package:dash_chat_2/dash_chat_2.dart'; +import 'package:fluentui_system_icons/fluentui_system_icons.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hbb/common.dart'; import 'package:flutter_hbb/models/chat_model.dart'; +import 'package:get/get.dart'; import 'package:provider/provider.dart'; import '../../mobile/pages/home_page.dart'; @@ -43,12 +45,28 @@ class ChatPage extends StatelessWidget implements PageShape { @override Widget build(BuildContext context) { return ChangeNotifierProvider.value( - value: chatModel, - child: Container( - color: Theme.of(context).scaffoldBackgroundColor, - child: Consumer(builder: (context, chatModel, child) { - final currentUser = chatModel.currentUser; - return Stack( + value: chatModel, + child: Container( + color: Theme.of(context).scaffoldBackgroundColor, + padding: EdgeInsets.all(20.0), + child: Consumer( + builder: (context, chatModel, child) { + final currentUser = chatModel.currentUser; + return Container( + padding: EdgeInsets.symmetric(vertical: 5.0), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10.0), + color: Theme.of(context).colorScheme.background, + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.2), + spreadRadius: 1, + blurRadius: 1, + offset: Offset(0, 1.5), // changes position of shadow + ), + ], + ), + child: Stack( children: [ LayoutBuilder(builder: (context, constraints) { final chat = DashChat( @@ -61,40 +79,40 @@ class ChatPage extends StatelessWidget implements PageShape { .messages[chatModel.currentID]?.chatMessages ?? [], inputOptions: InputOptions( - sendOnEnter: true, - focusNode: chatModel.inputNode, - inputTextStyle: TextStyle( - fontSize: 14, - color: Theme.of(context) - .textTheme - .titleLarge - ?.color), - inputDecoration: isDesktop - ? InputDecoration( - isDense: true, - hintText: - "${translate('Write a message')}", - filled: true, - fillColor: - Theme.of(context).colorScheme.background, - contentPadding: EdgeInsets.all(10), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(6), - borderSide: const BorderSide( - width: 0, - style: BorderStyle.none, - ), + sendOnEnter: true, + focusNode: chatModel.inputNode, + inputTextStyle: TextStyle( + fontSize: 14, + color: + Theme.of(context).textTheme.titleLarge?.color), + inputDecoration: isDesktop + ? InputDecoration( + isDense: true, + hintText: translate('Write a message'), + filled: true, + fillColor: + Theme.of(context).colorScheme.background, + contentPadding: EdgeInsets.all(10), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(10.0), + borderSide: const BorderSide( + width: 1, + style: BorderStyle.solid, ), - ) - : defaultInputDecoration( - hintText: - "${translate('Write a message')}", - fillColor: - Theme.of(context).colorScheme.background), - sendButtonBuilder: defaultSendButton( - padding: EdgeInsets.symmetric( - horizontal: 6, vertical: 0), - color: Theme.of(context).colorScheme.primary)), + ), + ) + : defaultInputDecoration( + hintText: translate('Write a message'), + fillColor: + Theme.of(context).colorScheme.background, + ), + sendButtonBuilder: defaultSendButton( + padding: + EdgeInsets.symmetric(horizontal: 6, vertical: 0), + color: Theme.of(context).colorScheme.primary, + icon: FluentIcons.send_24_filled, + ), + ), messageOptions: MessageOptions( showOtherUsersAvatar: false, textColor: Colors.white, @@ -104,32 +122,34 @@ class ChatPage extends StatelessWidget implements PageShape { message.user.id == currentUser.id; return Column( crossAxisAlignment: isOwnMessage - ? CrossAxisAlignment.end - : CrossAxisAlignment.start, + ? CrossAxisAlignment.start + : CrossAxisAlignment.end, children: [ Text(message.text, style: TextStyle(color: Colors.white)), - Padding( - padding: const EdgeInsets.only(top: 5), - child: Text( - "${message.createdAt.hour}:${message.createdAt.minute}", - style: TextStyle( - color: Colors.white, - fontSize: 10, - ), + Text( + "${message.createdAt.hour}:${message.createdAt.minute}", + style: TextStyle( + color: Colors.white, + fontSize: 8, ), - ), + ).marginOnly(top: 3), ], ); }, - messageDecorationBuilder: (_, __, ___) => - defaultMessageDecoration( - color: MyTheme.accent80, - borderTopLeft: 8, - borderTopRight: 8, - borderBottomRight: 8, - borderBottomLeft: 8, - )), + messageDecorationBuilder: (message, __, ___) { + final isOwnMessage = + message.user.id == currentUser.id; + return defaultMessageDecoration( + color: isOwnMessage + ? Color.fromARGB(170, 71, 97, 129) + : MyTheme.accent80, + borderTopLeft: 8, + borderTopRight: 8, + borderBottomRight: isOwnMessage ? 8 : 2, + borderBottomLeft: isOwnMessage ? 2 : 8, + ); + }), ); return SelectionArea(child: chat); }), @@ -148,9 +168,14 @@ class ChatPage extends StatelessWidget implements PageShape { style: TextStyle(color: MyTheme.accent50), ), ], - )), + ), + ), ], - ); - }))); + ), + ); + }, + ), + ), + ); } } diff --git a/flutter/lib/consts.dart b/flutter/lib/consts.dart index 1facf4e4b..d69b6cb3b 100644 --- a/flutter/lib/consts.dart +++ b/flutter/lib/consts.dart @@ -76,8 +76,8 @@ extension StringExtension on String { String get nonBreaking => replaceAll(' ', String.fromCharCode($nbsp)); } -const Size kConnectionManagerWindowSizeClosedChat = Size(300, 500); -const Size kConnectionManagerWindowSizeOpenChat = Size(600, 500); +const Size kConnectionManagerWindowSizeClosedChat = Size(300, 450); +const Size kConnectionManagerWindowSizeOpenChat = Size(700, 450); // Tabbar transition duration, now we remove the duration const Duration kTabTransitionDuration = Duration.zero; const double kEmptyMarginTop = 50; diff --git a/flutter/lib/desktop/pages/server_page.dart b/flutter/lib/desktop/pages/server_page.dart index 79aeaf896..01d26ff9c 100644 --- a/flutter/lib/desktop/pages/server_page.dart +++ b/flutter/lib/desktop/pages/server_page.dart @@ -12,6 +12,7 @@ import 'package:get/get.dart'; import 'package:provider/provider.dart'; import 'package:window_manager/window_manager.dart'; import 'package:flutter_svg/flutter_svg.dart'; +import 'package:fluentui_system_icons/fluentui_system_icons.dart'; import '../../common.dart'; import '../../common/widgets/chat_page.dart'; @@ -139,41 +140,45 @@ class ConnectionManagerState extends State { onPointerDown: pointerHandler, onPointerMove: pointerHandler, child: DesktopTab( - showTitle: false, - showMaximize: false, - showMinimize: true, - showClose: true, - onWindowCloseButton: handleWindowCloseButton, - controller: serverModel.tabController, - maxLabelWidth: 100, - tail: buildScrollJumper(), - selectedTabBackgroundColor: - Theme.of(context).hintColor.withOpacity(0.2), - tabBuilder: (key, icon, label, themeConf) { - final client = serverModel.clients.firstWhereOrNull( - (client) => client.id.toString() == key); - return Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Tooltip( - message: key, - waitDuration: Duration(seconds: 1), - child: label), - Obx(() => Offstage( - offstage: - !(client?.hasUnreadChatMessage.value ?? false), - child: - Icon(Icons.circle, color: Colors.red, size: 10))) - ], - ); - }, - pageViewBuilder: (pageView) => Row(children: [ - Expanded(child: pageView), - Consumer( - builder: (_, model, child) => model.isShowCMChatPage - ? Expanded(child: Scaffold(body: ChatPage())) - : Offstage()) - ]))); + showTitle: false, + showMaximize: false, + showMinimize: true, + showClose: true, + onWindowCloseButton: handleWindowCloseButton, + controller: serverModel.tabController, + maxLabelWidth: 100, + tail: buildScrollJumper(), + selectedTabBackgroundColor: + Theme.of(context).hintColor.withOpacity(0.2), + tabBuilder: (key, icon, label, themeConf) { + final client = serverModel.clients + .firstWhereOrNull((client) => client.id.toString() == key); + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Tooltip( + message: key, + waitDuration: Duration(seconds: 1), + child: label), + Obx(() => Offstage( + offstage: + !(client?.hasUnreadChatMessage.value ?? false), + child: Icon(Icons.circle, color: Colors.red, size: 10))) + ], + ); + }, + pageViewBuilder: (pageView) => Row( + children: [ + Consumer( + builder: (_, model, child) => model.isShowCMChatPage + ? Container( + width: 400, child: Scaffold(body: ChatPage())) + : Offstage()), + Expanded(child: pageView), + ], + ), + ), + ); } Widget buildTitleBar() { @@ -251,10 +256,11 @@ Widget buildConnectionCard(Client client) { ? Offstage() : _PrivilegeBoard(client: client), Expanded( - child: Align( - alignment: Alignment.bottomCenter, - child: _CmControlPanel(client: client), - )) + child: Align( + alignment: Alignment.bottomCenter, + child: _CmControlPanel(client: client), + ), + ) ], ).paddingSymmetric(vertical: 8.0, horizontal: 8.0)); } @@ -341,7 +347,7 @@ class _CmHeaderState extends State<_CmHeader> ], ), ), - margin: EdgeInsets.all(5.0), + margin: EdgeInsets.symmetric(horizontal: 5.0, vertical: 10.0), padding: EdgeInsets.all(10), child: Row( crossAxisAlignment: CrossAxisAlignment.start, @@ -416,7 +422,7 @@ class _CmHeaderState extends State<_CmHeader> onPressed: () => checkClickTime( client.id, () => gFFI.chatModel.toggleCMChatPage(client.id)), icon: Icon( - Icons.message_rounded, + FluentIcons.chat_32_filled, color: Colors.white, ), splashRadius: kDesktopIconButtonSplashRadius, @@ -442,25 +448,14 @@ class _PrivilegeBoard extends StatefulWidget { class _PrivilegeBoardState extends State<_PrivilegeBoard> { late final client = widget.client; - Widget buildPermissionTile(bool enabled, String assetPath, + Widget buildPermissionTile(bool enabled, IconData iconData, Function(bool)? onTap, String permissionText, String tooltipText) { return Row( children: [ Tooltip( message: tooltipText, - child: Container( - decoration: BoxDecoration( - color: MyTheme.accent, - borderRadius: BorderRadius.all( - Radius.circular(10.0), - ), - ), - child: SvgPicture.asset( - assetPath, - color: Colors.white, - width: 40.0, - height: 40.0, - ), + child: Icon( + iconData, ).paddingOnly(left: 5.0, bottom: 5.0), ).paddingOnly(right: 8.0), SizedBox( @@ -514,7 +509,7 @@ class _PrivilegeBoardState extends State<_PrivilegeBoard> { children: [ buildPermissionTile( client.keyboard, - "assets/keyboard.svg", + FluentIcons.keyboard_24_filled, (enabled) { bind.cmSwitchPermission( connId: client.id, name: "keyboard", enabled: enabled); @@ -527,7 +522,7 @@ class _PrivilegeBoardState extends State<_PrivilegeBoard> { ), buildPermissionTile( client.clipboard, - "assets/clipboard.svg", + FluentIcons.clipboard_24_filled, (enabled) { bind.cmSwitchPermission( connId: client.id, name: "clipboard", enabled: enabled); @@ -540,7 +535,7 @@ class _PrivilegeBoardState extends State<_PrivilegeBoard> { ), buildPermissionTile( client.audio, - "assets/audio.svg", + FluentIcons.speaker_1_24_filled, (enabled) { bind.cmSwitchPermission( connId: client.id, name: "audio", enabled: enabled); @@ -553,7 +548,7 @@ class _PrivilegeBoardState extends State<_PrivilegeBoard> { ), buildPermissionTile( client.file, - "assets/file.svg", + FluentIcons.arrow_sort_24_filled, (enabled) { bind.cmSwitchPermission( connId: client.id, name: "file", enabled: enabled); @@ -566,7 +561,7 @@ class _PrivilegeBoardState extends State<_PrivilegeBoard> { ), buildPermissionTile( client.restart, - "assets/restart.svg", + FluentIcons.arrow_clockwise_24_filled, (enabled) { bind.cmSwitchPermission( connId: client.id, name: "restart", enabled: enabled); @@ -579,7 +574,7 @@ class _PrivilegeBoardState extends State<_PrivilegeBoard> { ), buildPermissionTile( client.recording, - "assets/rec.svg", + FluentIcons.record_24_filled, (enabled) { bind.cmSwitchPermission( connId: client.id, name: "recording", enabled: enabled); @@ -681,11 +676,17 @@ class _CmControlPanel extends StatelessWidget { Row( children: [ Expanded( - child: buildButton(context, - color: Colors.redAccent, - onClick: handleDisconnect, - text: 'Disconnect', - textColor: Colors.white)), + child: buildButton(context, + color: Colors.redAccent, + onClick: handleDisconnect, + text: 'Disconnect', + icon: Icon( + FluentIcons.plug_disconnected_20_filled, + color: Colors.white, + size: 14, + ), + textColor: Colors.white), + ), ], ) ], @@ -789,16 +790,19 @@ class _CmControlPanel extends StatelessWidget { return Container( height: 30, decoration: BoxDecoration( - color: color, borderRadius: BorderRadius.circular(4), border: border), + color: color, + borderRadius: BorderRadius.circular(10.0), + border: border), child: InkWell( - onTap: () => checkClickTime(client.id, onClick), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Offstage(offstage: icon == null, child: icon), - textWidget, - ], - )), + onTap: () => checkClickTime(client.id, onClick), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Offstage(offstage: icon == null, child: icon).marginOnly(right: 5), + textWidget, + ], + ), + ), ).marginAll(4); }