mirror of https://github.com/CympleTech/ESSE.git
10 changed files with 501 additions and 47 deletions
@ -0,0 +1,169 @@
@@ -0,0 +1,169 @@
|
||||
import 'package:flutter/material.dart'; |
||||
|
||||
import 'package:esse/l10n/localizations.dart'; |
||||
import 'package:esse/widgets/button_text.dart'; |
||||
import 'package:esse/rpc.dart'; |
||||
import 'package:esse/apps/domain/models.dart'; |
||||
|
||||
class AccountDomainScreen extends StatefulWidget { |
||||
final String name; |
||||
|
||||
const AccountDomainScreen({Key? key, required this.name}) : super(key: key); |
||||
|
||||
@override |
||||
AccountDomainScreenState createState() => AccountDomainScreenState(); |
||||
} |
||||
|
||||
class AccountDomainScreenState extends State<AccountDomainScreen> { |
||||
Map<int, ProviderServer> _providers = {}; |
||||
|
||||
int _selected = -1; |
||||
bool _showName = false; |
||||
bool _exist = false; |
||||
bool _waiting = false; |
||||
|
||||
TextEditingController _nameController = new TextEditingController(); |
||||
FocusNode _nameFocus = new FocusNode(); |
||||
|
||||
_domainList(List params) { |
||||
this._providers.clear(); |
||||
params[0].forEach((param) { |
||||
this._providers[param[0]] = ProviderServer.fromList(param); |
||||
}); |
||||
setState(() {}); |
||||
} |
||||
|
||||
_domainRegisterSuccess(List params) { |
||||
// TODO toast. |
||||
Navigator.of(context).pushNamedAndRemoveUntil("/", (Route<dynamic> route) => false); |
||||
} |
||||
|
||||
_domainRegisterFailure(List _params) { |
||||
setState(() { |
||||
this._waiting = false; |
||||
this._exist = true; |
||||
this._showName = true; |
||||
}); |
||||
} |
||||
|
||||
@override |
||||
initState() { |
||||
super.initState(); |
||||
|
||||
rpc.addListener('domain-list', _domainList, false); |
||||
rpc.addListener('domain-register-success', _domainRegisterSuccess, false); |
||||
rpc.addListener('domain-register-failure', _domainRegisterFailure, false); |
||||
rpc.send('domain-list', []); |
||||
|
||||
_nameController.text = widget.name; |
||||
_nameFocus.addListener(() { |
||||
setState(() {}); |
||||
}); |
||||
} |
||||
|
||||
@override |
||||
Widget build(BuildContext context) { |
||||
final color = Theme.of(context).colorScheme; |
||||
final lang = AppLocalizations.of(context); |
||||
|
||||
if (this._selected < 0 && this._providers.length > 0) { |
||||
this._selected = 0; |
||||
this._providers.forEach((k, v) { |
||||
if (v.isDefault) { |
||||
this._selected = k; |
||||
} |
||||
}); |
||||
} |
||||
|
||||
final provider = this._providers.length > 0 |
||||
? this._providers[this._selected]! : ProviderServer.empty(); |
||||
|
||||
return Scaffold( |
||||
body: Center( |
||||
child: Column( |
||||
mainAxisAlignment: MainAxisAlignment.center, |
||||
crossAxisAlignment: CrossAxisAlignment.center, |
||||
children: [ |
||||
RichText( |
||||
text: TextSpan( |
||||
text: 'Register ', |
||||
style: TextStyle( |
||||
color: color.onSurface, fontSize: 20.0, fontWeight: FontWeight.bold |
||||
), |
||||
children: <TextSpan>[ |
||||
TextSpan(text: widget.name, style: TextStyle(color: Color(0xFF6174FF))), |
||||
TextSpan(text: ' to '), |
||||
TextSpan(text: provider.name, |
||||
style: TextStyle(color: Color(0xFF6174FF), fontStyle: FontStyle.italic) |
||||
), |
||||
TextSpan(text: ' ?'), |
||||
], |
||||
), |
||||
), |
||||
const SizedBox(height: 10.0), |
||||
Container( |
||||
width: 600.0, |
||||
child: Text('Tips: It will be sent to our built-in provider. Others can find your information (avatar, nickname, ESSEID, network address) by search the username, which can be managed and deleted in the personal ID later.'), |
||||
), |
||||
SizedBox( |
||||
height: 40.0, |
||||
child: Center(child: Text(this._exist ? lang.domainRegisterFailure : '', |
||||
style: TextStyle(color: Colors.red))), |
||||
), |
||||
if (this._showName) |
||||
Container( |
||||
width: 600.0, |
||||
height: 50.0, |
||||
padding: const EdgeInsets.symmetric(horizontal: 20.0), |
||||
decoration: BoxDecoration( |
||||
color: color.surface, |
||||
border: Border.all( |
||||
color: _nameFocus.hasFocus ? color.primary : color.surface), |
||||
borderRadius: BorderRadius.circular(10.0), |
||||
), |
||||
child: TextField( |
||||
style: TextStyle(fontSize: 16.0), |
||||
decoration: InputDecoration( |
||||
border: InputBorder.none, |
||||
hintText: lang.domainName, |
||||
), |
||||
controller: _nameController, |
||||
focusNode: _nameFocus |
||||
), |
||||
), |
||||
const SizedBox(height: 20.0), |
||||
ButtonText( |
||||
enable: this._providers.length > 0 && !this._waiting, |
||||
text: this._waiting ? lang.waiting : lang.send, |
||||
action: () { |
||||
final name = _nameController.text.trim(); |
||||
if (name.length > 0) { |
||||
rpc.send('domain-register', [provider.id, provider.addr, name, '']); |
||||
setState(() { |
||||
this._waiting = true; |
||||
this._exist = false; |
||||
}); |
||||
} |
||||
}), |
||||
const SizedBox(height: 20.0), |
||||
InkWell( |
||||
child: Container( |
||||
width: 600.0, |
||||
height: 50.0, |
||||
decoration: BoxDecoration( |
||||
border: Border.all(color: Color(0xFF6174FF)), |
||||
borderRadius: BorderRadius.circular(10.0)), |
||||
child: Center(child: Text(lang.skip, style: TextStyle( |
||||
fontSize: 20.0, color: Color(0xFF6174FF) |
||||
))), |
||||
), |
||||
onTap: () { |
||||
Navigator.of(context).pushNamedAndRemoveUntil("/", (Route<dynamic> route) => false); |
||||
} |
||||
), |
||||
] |
||||
) |
||||
) |
||||
); |
||||
} |
||||
} |
@ -0,0 +1,234 @@
@@ -0,0 +1,234 @@
|
||||
import 'dart:convert' show base64; |
||||
import 'dart:typed_data' show Uint8List; |
||||
import 'dart:ui' show Locale; |
||||
|
||||
import 'package:flutter/foundation.dart'; |
||||
import 'package:flutter/material.dart'; |
||||
import 'package:provider/provider.dart'; |
||||
|
||||
import 'package:esse/l10n/localizations.dart'; |
||||
import 'package:esse/utils/mnemonic.dart'; |
||||
import 'package:esse/utils/device_info.dart'; |
||||
import 'package:esse/widgets/button_text.dart'; |
||||
import 'package:esse/widgets/shadow_dialog.dart'; |
||||
import 'package:esse/widgets/show_pin.dart'; |
||||
import 'package:esse/widgets/select_avatar.dart'; |
||||
import 'package:esse/account.dart'; |
||||
import 'package:esse/global.dart'; |
||||
import 'package:esse/rpc.dart'; |
||||
import 'package:esse/provider.dart'; |
||||
import 'package:esse/options.dart'; |
||||
|
||||
import 'package:esse/pages/account_domain.dart'; |
||||
import 'package:esse/apps/device/provider.dart'; |
||||
import 'package:esse/apps/chat/provider.dart'; |
||||
import 'package:esse/apps/group_chat/provider.dart'; |
||||
|
||||
class AccountQuickPage extends StatefulWidget { |
||||
const AccountQuickPage({Key? key}) : super(key: key); |
||||
|
||||
@override |
||||
_AccountQuickPageState createState() => _AccountQuickPageState(); |
||||
} |
||||
|
||||
class _AccountQuickPageState extends State<AccountQuickPage> { |
||||
bool _registerChecked = false; |
||||
|
||||
TextEditingController _nameController = new TextEditingController(); |
||||
FocusNode _nameFocus = new FocusNode(); |
||||
|
||||
Uint8List? _imageBytes; |
||||
|
||||
@override |
||||
initState() { |
||||
super.initState(); |
||||
|
||||
_nameFocus.addListener(() { |
||||
setState(() {}); |
||||
}); |
||||
} |
||||
|
||||
@override |
||||
Widget build(BuildContext context) { |
||||
final color = Theme.of(context).colorScheme; |
||||
final lang = AppLocalizations.of(context); |
||||
final locale = context.read<Options>().locale; |
||||
|
||||
double maxHeight = (MediaQuery.of(context).size.height - 400) / 2; |
||||
if (maxHeight < 20.0) { |
||||
maxHeight = 20.0; |
||||
} |
||||
|
||||
return Scaffold( |
||||
body: SafeArea( |
||||
child: Container( |
||||
padding: const EdgeInsets.all(20.0), |
||||
child: SingleChildScrollView( |
||||
child: Column(crossAxisAlignment: CrossAxisAlignment.center, children: < |
||||
Widget>[ |
||||
_header(lang.newAccountTitle, () => Navigator.of(context).pop()), |
||||
SizedBox(height: maxHeight), |
||||
Column( |
||||
mainAxisAlignment: MainAxisAlignment.center, |
||||
crossAxisAlignment: CrossAxisAlignment.center, |
||||
children: <Widget>[ |
||||
newAccountAvatar(color, lang), |
||||
const SizedBox(height: 32.0), |
||||
Container( |
||||
height: 50.0, |
||||
width: 600.0, |
||||
padding: const EdgeInsets.symmetric(horizontal: 20.0), |
||||
decoration: BoxDecoration( |
||||
color: color.surface, |
||||
border: Border.all( |
||||
color: _nameFocus.hasFocus ? color.primary : color.surface), |
||||
borderRadius: BorderRadius.circular(10.0), |
||||
), |
||||
child: TextField( |
||||
style: TextStyle(fontSize: 16.0), |
||||
decoration: InputDecoration( |
||||
border: InputBorder.none, |
||||
hintText: lang.newAccountName, |
||||
), |
||||
controller: _nameController, |
||||
focusNode: _nameFocus, |
||||
onChanged: (value) { |
||||
if (value.length > 0) { |
||||
_registerChecked = true; |
||||
} else { |
||||
_registerChecked = false; |
||||
} |
||||
setState(() {}); |
||||
}), |
||||
), |
||||
const SizedBox(height: 32.0), |
||||
ButtonText(text: lang.ok, action: () => registerNewAction(locale), |
||||
enable: this._registerChecked), |
||||
_footer(lang.hasAccount, () => Navigator.of(context).pop()), |
||||
]) |
||||
]) |
||||
) |
||||
) |
||||
), |
||||
); |
||||
} |
||||
|
||||
Future<String> _getMnemonic(Locale locale) async { |
||||
final lang = MnemonicLangExtension.fromLocale(locale); |
||||
return await generateMnemonic(lang: lang); |
||||
} |
||||
|
||||
void registerNewAction(Locale locale) async { |
||||
final mnemonic = await _getMnemonic(locale); |
||||
final name = _nameController.text; |
||||
final avatar = _imageBytes != null ? base64.encode(_imageBytes!) : ""; |
||||
final info = await deviceInfo(); |
||||
final lock = ''; |
||||
|
||||
if (!_registerChecked) { |
||||
return; |
||||
} |
||||
|
||||
// send to core node service by rpc. |
||||
final res = await httpPost(Global.httpRpc, |
||||
'account-create', [name, lock, mnemonic, avatar, info[0], info[1]]); |
||||
|
||||
if (res.isOk) { |
||||
// save this User |
||||
final account = Account(res.params[0], name, lock, avatar); |
||||
|
||||
Provider.of<AccountProvider>(context, listen: false).addAccount(account); |
||||
Provider.of<DeviceProvider>(context, listen: false).updateActived(); |
||||
Provider.of<ChatProvider>(context, listen: false).updateActived(); |
||||
Provider.of<GroupChatProvider>(context, listen: false).updateActived(); |
||||
|
||||
Navigator.push(context, MaterialPageRoute(builder: (_) => AccountDomainScreen( |
||||
name: name, |
||||
))); |
||||
} else { |
||||
// TODO tostor error |
||||
print(res.error); |
||||
} |
||||
} |
||||
|
||||
Widget newAccountAvatar(color, lang) { |
||||
return Container( |
||||
width: 100, |
||||
height: 100, |
||||
decoration: BoxDecoration( |
||||
color: color.surface, |
||||
image: _imageBytes != null ? DecorationImage( |
||||
image: MemoryImage(_imageBytes!), |
||||
fit: BoxFit.cover, |
||||
) : null, |
||||
borderRadius: BorderRadius.circular(15.0)), |
||||
child: Stack( |
||||
alignment: Alignment.center, |
||||
children: <Widget>[ |
||||
if (_imageBytes == null) |
||||
Icon(Icons.camera_alt, size: 47.0, color: Color(0xFFADB0BB)), |
||||
Positioned( |
||||
bottom: -1.0, |
||||
right: -1.0, |
||||
child: InkWell( |
||||
child: Container( |
||||
decoration: const ShapeDecoration( |
||||
color: Colors.white, |
||||
shape: CircleBorder(), |
||||
), |
||||
child: Icon(Icons.add_circle, |
||||
size: 32.0, color: color.primary), |
||||
), |
||||
onTap: () => selectAvatar(context, (bytes) => setState(() { |
||||
_imageBytes = bytes; |
||||
})), |
||||
), |
||||
), |
||||
], |
||||
), |
||||
); |
||||
} |
||||
} |
||||
|
||||
Widget _header(String value, VoidCallback callback) { |
||||
return Container( |
||||
width: 700.0, |
||||
child: Row( |
||||
mainAxisAlignment: MainAxisAlignment.start, |
||||
crossAxisAlignment: CrossAxisAlignment.center, |
||||
children: [ |
||||
GestureDetector( |
||||
onTap: callback, |
||||
child: Container( |
||||
width: 40.0, |
||||
height: 40.0, |
||||
decoration: BoxDecoration( |
||||
color: Color(0xFF6174FF), |
||||
borderRadius: BorderRadius.circular(10.0)), |
||||
child: Center(child: Icon(Icons.arrow_back, color: Colors.white)), |
||||
)), |
||||
const SizedBox(width: 32.0), |
||||
Text( |
||||
value, |
||||
style: TextStyle( |
||||
fontSize: 20.0, |
||||
fontWeight: FontWeight.bold, |
||||
), |
||||
), |
||||
])); |
||||
} |
||||
|
||||
Widget _footer(String text1, VoidCallback callback) { |
||||
return Padding( |
||||
padding: const EdgeInsets.only(top: 20), |
||||
child: Center( |
||||
child: TextButton( |
||||
onPressed: callback, |
||||
child: Text( |
||||
text1, |
||||
style: TextStyle(fontSize: 16), |
||||
), |
||||
), |
||||
), |
||||
); |
||||
} |
Loading…
Reference in new issue