From 09e44426a121d14c0425ca499c7a06ddc8d96ee7 Mon Sep 17 00:00:00 2001 From: Sun Date: Sat, 29 May 2021 23:01:12 +0800 Subject: [PATCH] change group chat UI --- lib/apps/group_chat/add.dart | 486 ++++++++++++++++++--------------- lib/apps/service/models.dart | 2 +- lib/l10n/localizations.dart | 18 ++ lib/l10n/localizations_en.dart | 38 ++- lib/l10n/localizations_zh.dart | 38 ++- 5 files changed, 362 insertions(+), 220 deletions(-) diff --git a/lib/apps/group_chat/add.dart b/lib/apps/group_chat/add.dart index b5d1e61..f71e631 100644 --- a/lib/apps/group_chat/add.dart +++ b/lib/apps/group_chat/add.dart @@ -33,11 +33,9 @@ class GroupAddPage extends StatefulWidget { class _GroupAddPageState extends State { TextEditingController _joinIdController = TextEditingController(); TextEditingController _joinAddrController = TextEditingController(); - TextEditingController _joinRemarkController = TextEditingController(); TextEditingController _joinNameController = TextEditingController(); FocusNode _joinIdFocus = FocusNode(); FocusNode _joinAddrFocus = FocusNode(); - FocusNode _joinRemarkFocus = FocusNode(); TextEditingController _createAddrController = TextEditingController(); TextEditingController _createNameController = TextEditingController(); @@ -47,6 +45,8 @@ class _GroupAddPageState extends State { FocusNode _createNameFocus = FocusNode(); FocusNode _createBioFocus = FocusNode(); FocusNode _createKeyFocus = FocusNode(); + + int _groupAddr = 0; int _groupType = 0; bool _groupNeedAgree = false; bool _groupHasKey = true; @@ -57,6 +57,24 @@ class _GroupAddPageState extends State { bool _requestsLoadMore = true; + // 0 => encrypted, 1 => common, 2 => open. + Widget _groupAddrWidget(String text, int value, ColorScheme color) { + return Row( + children: [ + Radio( + value: value, + groupValue: _groupAddr, + onChanged: (n) => setState(() { + _groupAddr = n; + }), + ), + _groupAddr == value + ? Text(text, style: TextStyle(color: color.primary)) + : Text(text), + ] + ); + } + // 0 => encrypted, 1 => common, 2 => open. Widget _groupTypeWidget(String text, int value, ColorScheme color) { return Row( @@ -126,13 +144,11 @@ class _GroupAddPageState extends State { addr = addr.substring(2); } var name = _joinNameController.text; - var remark = _joinRemarkController.text; - context.read().join(id, addr, name, remark); + context.read().join(id, addr, name, ""); setState(() { _joinIdController.text = ''; _joinAddrController.text = ''; _joinNameController.text = ''; - _joinRemarkController.text = ''; }); } @@ -167,9 +183,6 @@ class _GroupAddPageState extends State { _joinAddrFocus.addListener(() { setState(() {}); }); - _joinRemarkFocus.addListener(() { - setState(() {}); - }); _createAddrFocus.addListener(() { setState(() {}); }); @@ -214,7 +227,7 @@ class _GroupAddPageState extends State { title: Row( children: [ Expanded( - child: Text('Add Group Chat', + child: Text(lang.groupChatAdd, style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20.0)), ), TextButton( @@ -233,7 +246,7 @@ class _GroupAddPageState extends State { children: [ Icon(Icons.add_box_rounded, color: color.primary), const SizedBox(width: 8.0), - Text('Join A Group', style: TextStyle(color: color.primary)) + Text(lang.groupJoin, style: TextStyle(color: color.primary)) ]) ), Tab( @@ -242,7 +255,7 @@ class _GroupAddPageState extends State { children: [ Icon(Icons.create_rounded, color: color.primary), const SizedBox(width: 8.0), - Text('Create A Group', style: TextStyle(color: color.primary)) + Text(lang.groupCreate, style: TextStyle(color: color.primary)) ]) ), ], @@ -253,226 +266,265 @@ class _GroupAddPageState extends State { Container( padding: const EdgeInsets.all(20), child: SingleChildScrollView( - child: Form( - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - InputText( - icon: Icons.groups, - text: 'Group ID', - controller: _joinIdController, - focus: _joinIdFocus), - - const SizedBox(height: 20.0), - InputText( - icon: Icons.location_on, - text: lang.address, - controller: _joinAddrController, - focus: _joinAddrFocus), - const SizedBox(height: 20.0), - InputText( - icon: Icons.turned_in, - text: lang.remark, - controller: _joinRemarkController, - focus: _joinRemarkFocus), - const SizedBox(height: 20.0), - ButtonText(action: _join, text: lang.send, width: 600.0), - const SizedBox(height: 20.0), - const Divider(height: 1.0, color: Color(0x40ADB0BB)), - const SizedBox(height: 10.0), - if (requests.isNotEmpty) - Container( - width: 600.0, - child: ListView.builder( - itemCount: requestKeys.length, - shrinkWrap: true, - physics: ClampingScrollPhysics(), - scrollDirection: Axis.vertical, - itemBuilder: (BuildContext context, int index) => - _RequestItem(request: requests[requestKeys[index]]), - ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox(height: 20.0), + InputText( + icon: Icons.groups, + text: lang.groupChatId, + controller: _joinIdController, + focus: _joinIdFocus), + const SizedBox(height: 20.0), + InputText( + icon: Icons.location_on, + text: lang.groupChatAddr, + controller: _joinAddrController, + focus: _joinAddrFocus), + const SizedBox(height: 20.0), + ButtonText(action: _join, text: lang.send, width: 600.0), + const SizedBox(height: 20.0), + const Divider(height: 1.0, color: Color(0x40ADB0BB)), + const SizedBox(height: 10.0), + if (requests.isNotEmpty) + Container( + width: 600.0, + child: ListView.builder( + itemCount: requestKeys.length, + shrinkWrap: true, + physics: ClampingScrollPhysics(), + scrollDirection: Axis.vertical, + itemBuilder: (BuildContext context, int index) => + _RequestItem(request: requests[requestKeys[index]]), ), - if (_requestsLoadMore) - TextButton( - onPressed: () { - provider.requestList(true); - setState(() { - _requestsLoadMore = false; - }); - }, - child: Text('load more...', style: TextStyle(fontSize: 14.0)), - ), - ], - ), + ), + if (_requestsLoadMore) + TextButton( + onPressed: () { + provider.requestList(true); + setState(() { + _requestsLoadMore = false; + }); + }, + child: Text(lang.loadMore, style: TextStyle(fontSize: 14.0)), + ), + ], ), ), ), Container( padding: const EdgeInsets.all(20), child: SingleChildScrollView( - child: Form( - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Container( - height: 50.0, - width: 600.0, - child: Row( - children: [ - Expanded( - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 20.0), - decoration: BoxDecoration( - color: color.surface, - border: Border.all(color: _createAddrFocus.hasFocus - ? color.primary : color.surface), - borderRadius: BorderRadius.circular(15.0), - ), - child: TextField( - style: TextStyle(fontSize: 16.0), - decoration: InputDecoration( - border: InputBorder.none, - hintText: lang.address), - controller: _createAddrController, - focusNode: _createAddrFocus, - onSubmitted: (_v) => _checkAddrPermission(), - onChanged: (v) { - if (v.length > 0) { - setState(() { - _addrChecked = true; - }); - } - }), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + width: 600.0, + padding: const EdgeInsets.all(10.0), + alignment: Alignment.centerLeft, + child: Text('1. ' + lang.groupChatAddr, textAlign: TextAlign.left, + style: Theme.of(context).textTheme.title), + ), + Container( + padding: EdgeInsets.only(bottom: 10.0), + width: 600.0, + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + _groupAddrWidget(lang.deviceRemote, 0, color), + _groupAddrWidget(lang.deviceLocal, 1, color), + ] + ) + ), + if (_groupAddr == 0) + Container( + height: 50.0, + width: 600.0, + child: Row( + children: [ + Expanded( + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 20.0), + decoration: BoxDecoration( + color: color.surface, + border: Border.all(color: _createAddrFocus.hasFocus + ? color.primary : color.surface), + borderRadius: BorderRadius.circular(15.0), ), + child: TextField( + style: TextStyle(fontSize: 16.0), + decoration: InputDecoration( + border: InputBorder.none, + hintText: lang.address), + controller: _createAddrController, + focusNode: _createAddrFocus, + onSubmitted: (_v) => _checkAddrPermission(), + onChanged: (v) { + if (v.length > 0) { + setState(() { + _addrChecked = true; + }); + } + }), ), - if (checkOk) - Container( - padding: const EdgeInsets.only(left: 8.0), - child: Icon(Icons.cloud_done_rounded, - color: Colors.green), - ), - const SizedBox(width: 8.0), - Container( - width: 100.0, - child: InkWell( - onTap: _addrChecked ? _checkGroupAddr : null, - child: Container( - height: 45.0, - decoration: BoxDecoration( - color: Color(0xFF6174FF), - borderRadius: BorderRadius.circular(15.0)), - child: Center( - child: Text(lang.search, - style: TextStyle(fontSize: 16.0, color: Colors.white))), - ))), - ])), - const SizedBox(height: 8.0), - Text(checkLang, style: TextStyle(fontSize: 14.0, - color: checkOk ? Colors.green : Colors.red)), - Container( - width: 600.0, - padding: const EdgeInsets.all(10.0), - alignment: Alignment.centerLeft, - child: Text('Group Info', textAlign: TextAlign.left, style: TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold)), - ), - Container( - width: 100.0, - height: 100.0, - margin: const EdgeInsets.symmetric(vertical: 10.0), - decoration: BoxDecoration( - color: color.surface, - borderRadius: BorderRadius.circular(15.0)), - child: Stack( - alignment: Alignment.center, - children: [ - Icon(Icons.camera_alt, - size: 47.0, color: Color(0xFFADB0BB)), - Positioned( - bottom: -1.0, - right: -1.0, - child: InkWell( - child: Icon(Icons.add_circle, - size: 32.0, color: color.primary), - onTap: null, //() => _getImage(context, account.name, color, lang), - ) - ), - ], - ), - ), - Container( - padding: EdgeInsets.symmetric(vertical: 10.0), - width: 600.0, - child: Row( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - _groupTypeWidget('Encrypted', 0, color), - _groupTypeWidget('Common', 1, color), - _groupTypeWidget('Open', 2, color), - ] - ) + ), + if (checkOk) + Container( + padding: const EdgeInsets.only(left: 8.0), + child: Icon(Icons.cloud_done_rounded, + color: Colors.green), + ), + const SizedBox(width: 8.0), + InkWell( + onTap: _addrChecked ? _checkGroupAddr : null, + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 20.0), + height: 45.0, + decoration: BoxDecoration( + color: Color(0xFF6174FF), + borderRadius: BorderRadius.circular(15.0)), + child: Center( + child: Text(lang.search, + style: TextStyle(fontSize: 16.0, color: Colors.white))), + )), + const SizedBox(width: 8.0), + InkWell( + onTap: _addrChecked ? _checkGroupAddr : null, + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 20.0), + height: 45.0, + decoration: BoxDecoration( + color: Color(0xFF6174FF), + borderRadius: BorderRadius.circular(15.0)), + child: Center( + child: Text(lang.add, + style: TextStyle(fontSize: 16.0, color: Colors.white))), + )), + ])), + const SizedBox(height: 8.0), + Text(checkLang, style: TextStyle(fontSize: 14.0, + color: checkOk ? Colors.green : Colors.red)), + Container( + width: 600.0, + padding: const EdgeInsets.all(10.0), + alignment: Alignment.centerLeft, + child: Text('2. ' + lang.groupChatInfo, textAlign: TextAlign.left, + style: Theme.of(context).textTheme.title), + ), + Container( + width: 100.0, + height: 100.0, + margin: const EdgeInsets.symmetric(vertical: 10.0), + decoration: BoxDecoration( + color: color.surface, + borderRadius: BorderRadius.circular(15.0)), + child: Stack( + alignment: Alignment.center, + children: [ + Icon(Icons.camera_alt, + size: 47.0, color: Color(0xFFADB0BB)), + Positioned( + bottom: -1.0, + right: -1.0, + child: InkWell( + child: Icon(Icons.add_circle, + size: 32.0, color: color.primary), + onTap: null, //() => _getImage(context, account.name, color, lang), + ) + ), + ], ), - Container( - padding: EdgeInsets.symmetric(vertical: 10.0), - child: InputText( - icon: Icons.account_box, - text: 'Group Name', - controller: _createNameController, - focus: _createNameFocus), + ), + Container( + padding: EdgeInsets.symmetric(vertical: 10.0), + width: 600.0, + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + _groupTypeWidget(lang.groupTypeEncrypted, 0, color), + _groupTypeWidget(lang.groupTypePrivate, 1, color), + _groupTypeWidget(lang.groupTypeOpen, 2, color), + ] + ) + ), + Container( + width: 600.0, + padding: const EdgeInsets.all(12.0), + margin: const EdgeInsets.only(bottom: 10.0), + decoration: BoxDecoration(color: color.surface, + borderRadius: BorderRadius.circular(15.0) ), - Container( - padding: EdgeInsets.symmetric(vertical: 10.0), - child: InputText( - icon: Icons.campaign, - text: 'Group Bio', - controller: _createBioController, - focus: _createBioFocus), + child: Text( + _groupType == 0 ? lang.groupTypeEncryptedInfo + : (_groupType == 1 ? lang.groupTypePrivateInfo + : lang.groupTypeOpenInfo), + style: TextStyle(fontSize: 14.0, height: 1.5, + fontStyle: FontStyle.italic), + textAlign: TextAlign.center, ), - if (_groupHasKey) - Container( - padding: EdgeInsets.symmetric(vertical: 10.0), - child: InputText( - icon: Icons.enhanced_encryption, - text: 'Encrypted Key', - controller: _createKeyController, - focus: _createKeyFocus), + ), + Container( + padding: EdgeInsets.symmetric(vertical: 10.0), + child: InputText( + icon: Icons.account_box, + text: lang.groupChatName, + controller: _createNameController, + focus: _createNameFocus), + ), + Container( + padding: EdgeInsets.symmetric(vertical: 10.0), + child: InputText( + icon: Icons.campaign, + text: lang.groupChatBio, + controller: _createBioController, + focus: _createBioFocus), + ), + if (_groupHasKey) + Container( + padding: EdgeInsets.symmetric(vertical: 10.0), + child: InputText( + icon: Icons.enhanced_encryption, + text: lang.groupChatKey, + controller: _createKeyController, + focus: _createKeyFocus), + ), + if (_groupHasNeedAgree) + Container( + height: 50.0, + width: 600.0, + child: Row( + children: [ + Switch( + value: _groupNeedAgree, + onChanged: (value) { + setState(() { + _groupNeedAgree = value; + }); + }, + ), + Text(lang.groupRequireConsent) + ] ), - if (_groupHasNeedAgree) - Container( - height: 50.0, - width: 600.0, - child: Row( - children: [ - Switch( - value: _groupNeedAgree, - onChanged: (value) { - setState(() { - _groupNeedAgree = value; - }); - }, - ), - Text('Need Group Manager Agree.') - ] - ), + ), + const SizedBox(height: 20.0), + ButtonText(action: _create, text: lang.create, width: 600.0), + const SizedBox(height: 20.0), + const Divider(height: 1.0, color: Color(0x40ADB0BB)), + const SizedBox(height: 10.0), + Container( + width: 600.0, + child: ListView.builder( + itemCount: createKeys.length, + shrinkWrap: true, + physics: ClampingScrollPhysics(), + scrollDirection: Axis.vertical, + itemBuilder: (BuildContext context, int index) => + _CreateItem(group: groups[createKeys[index]], name: _myName), ), - const SizedBox(height: 20.0), - ButtonText(action: _create, text: lang.create, width: 600.0), - const SizedBox(height: 20.0), - const Divider(height: 1.0, color: Color(0x40ADB0BB)), - const SizedBox(height: 10.0), - Container( - width: 600.0, - child: ListView.builder( - itemCount: createKeys.length, - shrinkWrap: true, - physics: ClampingScrollPhysics(), - scrollDirection: Axis.vertical, - itemBuilder: (BuildContext context, int index) => - _CreateItem(group: groups[createKeys[index]], name: _myName), - ), - ) - ], - ), + ) + ], ), ), ), diff --git a/lib/apps/service/models.dart b/lib/apps/service/models.dart index 639a6af..c25f333 100644 --- a/lib/apps/service/models.dart +++ b/lib/apps/service/models.dart @@ -23,7 +23,7 @@ extension InnerServiceExtension on InnerService { case InnerService.Assistant: return [lang.assistant, lang.assistantBio, 'assets/logo/logo_assistant.png']; case InnerService.GroupChat: - return [lang.groupChat, lang.groupChatBio, 'assets/logo/logo_group_chat.png']; + return [lang.groupChat, lang.groupChatIntro, 'assets/logo/logo_group_chat.png']; } } diff --git a/lib/l10n/localizations.dart b/lib/l10n/localizations.dart index 484bd1b..f71d08b 100644 --- a/lib/l10n/localizations.dart +++ b/lib/l10n/localizations.dart @@ -81,6 +81,7 @@ abstract class AppLocalizations { String get unknown; String get create; String get exit; + String get loadMore; // theme String get themeDark; @@ -138,6 +139,7 @@ abstract class AppLocalizations { String get deviceTip; String get deviceChangeWs; String get deviceChangeHttp; + String get deviceRemote; String get deviceLocal; String get deviceQrcode; String get deviceQrcodeIntro; @@ -163,12 +165,28 @@ abstract class AppLocalizations { String get assistant; String get assistantBio; String get groupChat; + String get groupChatAdd; + String get groupChatIntro; + String get groupChatId; + String get groupChatName; + String get groupChatKey; + String get groupChatAddr; + String get groupChatInfo; String get groupChatBio; + String get groupJoin; + String get groupCreate; + String get groupTypeEncrypted; + String get groupTypeEncryptedInfo; + String get groupTypePrivate; + String get groupTypePrivateInfo; + String get groupTypeOpen; + String get groupTypeOpenInfo; String get groupCheckTypeAllow; String get groupCheckTypeNone; String get groupCheckTypeSuspend; String get groupCheckTypeDeny; String get members; + String get groupRequireConsent; } class _AppLocalizationsDelegate diff --git a/lib/l10n/localizations_en.dart b/lib/l10n/localizations_en.dart index 9241703..09f3538 100644 --- a/lib/l10n/localizations_en.dart +++ b/lib/l10n/localizations_en.dart @@ -86,6 +86,8 @@ class AppLocalizationsEn extends AppLocalizations { String get create => 'Create'; @override String get exit => 'Exit'; + @override + String get loadMore => 'Load more...'; // theme @override @@ -189,6 +191,8 @@ class AppLocalizationsEn extends AppLocalizations { @override String get deviceChangeHttp => 'Change http'; @override + String get deviceRemote => 'Remote'; + @override String get deviceLocal => 'Local'; @override String get deviceQrcode => 'Device QR Code'; @@ -237,7 +241,37 @@ class AppLocalizationsEn extends AppLocalizations { @override String get groupChat => 'Group Chats'; @override - String get groupChatBio => 'Multiple group chats'; + String get groupChatAdd => 'Add Group Chat'; + @override + String get groupChatIntro => 'Multiple group chats'; + @override + String get groupChatId => 'Group ID'; + @override + String get groupChatName => 'Group Name'; + @override + String get groupChatKey => 'Encrypted Key'; + @override + String get groupChatAddr => 'Group Address'; + @override + String get groupChatInfo => 'Group Information'; + @override + String get groupChatBio => 'Group Bio'; + @override + String get groupJoin => 'Join Open Group'; + @override + String get groupCreate => 'Create Group'; + @override + String get groupTypeEncrypted => 'Encrypted'; + @override + String get groupTypeEncryptedInfo => "Encrypted: It can only be joined by the invitation of members, and the manager's consent is optional, Members hold a zero-knowledge proof about the key to enter; Group information and messages are encrypted and stored on the server, and the server NOT has secret key, INVISIBLE information."; + @override + String get groupTypePrivate => 'Private'; + @override + String get groupTypePrivateInfo => "Private: It can only be joined by the invitation of members, and the manager's consent is optional; Group information and messages are stored on the server, VISIBLE information."; + @override + String get groupTypeOpen => 'Open'; + @override + String get groupTypeOpenInfo => 'Open: Any member who has group information can freely enter and leave; Group information and messages are stored on the server, VISIBLE information.'; @override String get groupCheckTypeAllow => 'You can create a new group chat'; @override @@ -248,4 +282,6 @@ class AppLocalizationsEn extends AppLocalizations { String get groupCheckTypeDeny => 'No permission to create here'; @override String get members => 'Members'; + @override + String get groupRequireConsent => "Requires manager's consent"; } diff --git a/lib/l10n/localizations_zh.dart b/lib/l10n/localizations_zh.dart index c4e002d..3b81098 100644 --- a/lib/l10n/localizations_zh.dart +++ b/lib/l10n/localizations_zh.dart @@ -86,6 +86,8 @@ class AppLocalizationsZh extends AppLocalizations { String get create => '创建'; @override String get exit => '退出'; + @override + String get loadMore => '加载更多'; // theme @override @@ -189,6 +191,8 @@ class AppLocalizationsZh extends AppLocalizations { @override String get deviceChangeHttp => '修改 Http 接口'; @override + String get deviceRemote => '远程'; + @override String get deviceLocal => '本机'; @override String get deviceQrcode => '设备二维码'; @@ -237,7 +241,37 @@ class AppLocalizationsZh extends AppLocalizations { @override String get groupChat => '群聊'; @override - String get groupChatBio => '各种各样的群聊'; + String get groupChatAdd => '添加群聊'; + @override + String get groupChatIntro => '各种各样的群聊'; + @override + String get groupChatId => '群ID'; + @override + String get groupChatAddr => '群聊地址'; + @override + String get groupChatName => '群名称'; + @override + String get groupChatKey => '加密密码'; + @override + String get groupChatInfo => '群聊信息'; + @override + String get groupChatBio => '群公告'; + @override + String get groupJoin => '加入公开群'; + @override + String get groupCreate => '新建群'; + @override + String get groupTypeEncrypted => '加密'; + @override + String get groupTypeEncryptedInfo => '加密的群聊:只能通过群成员邀请加入,可选是否需要管理员同意,成员需持有密钥的零知识证明方可进入;群信息和消息全部加密存储在服务端,服务端无密钥,不可见信息。'; + @override + String get groupTypePrivate => '私有'; + @override + String get groupTypePrivateInfo => '私有的群聊:只能通过群成员邀请加入,可选是否需要管理员同意;群信息和消息存储在服务端,服务端可见信息。'; + @override + String get groupTypeOpen => '公开'; + @override + String get groupTypeOpenInfo => '公开的群聊:任何拥有群信息的成员均可自由进出;群信息和消息存储在服务端,服务端可见信息。'; @override String get groupCheckTypeAllow => '可以创建新的群聊'; @override @@ -248,4 +282,6 @@ class AppLocalizationsZh extends AppLocalizations { String get groupCheckTypeDeny => '没有权限在此创建群聊'; @override String get members => '成员'; + @override + String get groupRequireConsent => "需要管理员同意"; }