Browse Source

Add check register to default domain after genereate account & add quick create account

pull/18/head
Sun 4 years ago
parent
commit
a755ed2443
  1. 2
      lib/l10n/localizations.dart
  2. 4
      lib/l10n/localizations_en.dart
  3. 4
      lib/l10n/localizations_zh.dart
  4. 169
      lib/pages/account_domain.dart
  5. 19
      lib/pages/account_generate.dart
  6. 234
      lib/pages/account_quick.dart
  7. 7
      lib/pages/account_restore.dart
  8. 16
      lib/pages/setting/profile.dart
  9. 81
      lib/security.dart
  10. 12
      lib/utils/mnemonic.dart

2
lib/l10n/localizations.dart

@ -95,6 +95,7 @@ abstract class AppLocalizations { @@ -95,6 +95,7 @@ abstract class AppLocalizations {
String get input;
String get waiting;
String get notExist;
String get skip;
// theme
String get themeDark;
@ -108,6 +109,7 @@ abstract class AppLocalizations { @@ -108,6 +109,7 @@ abstract class AppLocalizations {
String get loginRestore;
String get loginRestoreOnline;
String get loginNew;
String get loginQuick;
String get newMnemonicTitle;
String get newMnemonicInput;
String get hasAccount;

4
lib/l10n/localizations_en.dart

@ -114,6 +114,8 @@ class AppLocalizationsEn extends AppLocalizations { @@ -114,6 +114,8 @@ class AppLocalizationsEn extends AppLocalizations {
String get waiting => 'Waiting';
@override
String get notExist => 'User not exist.';
@override
String get skip => 'Skip';
// theme
@override
@ -135,6 +137,8 @@ class AppLocalizationsEn extends AppLocalizations { @@ -135,6 +137,8 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get loginNew => 'Create Account';
@override
String get loginQuick => 'Quickly Create';
@override
String get newMnemonicTitle => 'Mnemonic code (DID)';
@override
String get newMnemonicInput => 'Generate';

4
lib/l10n/localizations_zh.dart

@ -114,6 +114,8 @@ class AppLocalizationsZh extends AppLocalizations { @@ -114,6 +114,8 @@ class AppLocalizationsZh extends AppLocalizations {
String get waiting => '等待中';
@override
String get notExist => '用户不存在。';
@override
String get skip => '跳过';
// theme
@override
@ -135,6 +137,8 @@ class AppLocalizationsZh extends AppLocalizations { @@ -135,6 +137,8 @@ class AppLocalizationsZh extends AppLocalizations {
@override
String get loginNew => '新建账户';
@override
String get loginQuick => '快速新建';
@override
String get newMnemonicTitle => '助记词(DID)';
@override
String get newMnemonicInput => '生成';

169
lib/pages/account_domain.dart

@ -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);
}
),
]
)
)
);
}
}

19
lib/pages/account_generate.dart

@ -17,6 +17,7 @@ import 'package:esse/global.dart'; @@ -17,6 +17,7 @@ import 'package:esse/global.dart';
import 'package:esse/rpc.dart';
import 'package:esse/provider.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';
@ -44,6 +45,7 @@ class _AccountGeneratePageState extends State<AccountGeneratePage> { @@ -44,6 +45,7 @@ class _AccountGeneratePageState extends State<AccountGeneratePage> {
@override
initState() {
super.initState();
_nameFocus.addListener(() {
setState(() {});
});
@ -103,7 +105,9 @@ class _AccountGeneratePageState extends State<AccountGeneratePage> { @@ -103,7 +105,9 @@ class _AccountGeneratePageState extends State<AccountGeneratePage> {
Provider.of<ChatProvider>(context, listen: false).updateActived();
Provider.of<GroupChatProvider>(context, listen: false).updateActived();
Navigator.of(context).pushNamedAndRemoveUntil("/", (Route<dynamic> route) => false);
Navigator.push(context, MaterialPageRoute(builder: (_) => AccountDomainScreen(
name: name,
)));
} else {
// TODO tostor error
print(res.error);
@ -142,7 +146,7 @@ class _AccountGeneratePageState extends State<AccountGeneratePage> { @@ -142,7 +146,7 @@ class _AccountGeneratePageState extends State<AccountGeneratePage> {
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
width: 450.0,
width: 600.0,
child: Row(children: [
Expanded(
child: Container(
@ -197,7 +201,7 @@ class _AccountGeneratePageState extends State<AccountGeneratePage> { @@ -197,7 +201,7 @@ class _AccountGeneratePageState extends State<AccountGeneratePage> {
])),
const SizedBox(height: 32.0),
Container(
width: 450.0,
width: 600.0,
alignment: Alignment.center,
constraints: BoxConstraints(minHeight: 170.0),
padding: const EdgeInsets.all(10.0),
@ -214,7 +218,6 @@ class _AccountGeneratePageState extends State<AccountGeneratePage> { @@ -214,7 +218,6 @@ class _AccountGeneratePageState extends State<AccountGeneratePage> {
),
const SizedBox(height: 32.0),
ButtonText(
width: 450,
text: lang.next,
enable: _mnemonicChecked,
action: () {
@ -245,7 +248,7 @@ class _AccountGeneratePageState extends State<AccountGeneratePage> { @@ -245,7 +248,7 @@ class _AccountGeneratePageState extends State<AccountGeneratePage> {
const SizedBox(height: 32.0),
Container(
height: 50.0,
width: 450.0,
width: 600.0,
padding: const EdgeInsets.symmetric(horizontal: 20.0),
decoration: BoxDecoration(
color: color.surface,
@ -271,7 +274,7 @@ class _AccountGeneratePageState extends State<AccountGeneratePage> { @@ -271,7 +274,7 @@ class _AccountGeneratePageState extends State<AccountGeneratePage> {
}),
),
const SizedBox(height: 32.0),
ButtonText(width: 450, text: lang.ok, action: () => registerNewAction(lang.setPin),
ButtonText(text: lang.ok, action: () => registerNewAction(lang.setPin),
enable: this._registerChecked),
_footer(lang.hasAccount, () => Navigator.of(context).pop()),
])
@ -299,8 +302,8 @@ class _AccountGeneratePageState extends State<AccountGeneratePage> { @@ -299,8 +302,8 @@ class _AccountGeneratePageState extends State<AccountGeneratePage> {
right: -1.0,
child: InkWell(
child: Container(
decoration: const ShapeDecoration(
color: Colors.white,
decoration: ShapeDecoration(
color: color.surface,
shape: CircleBorder(),
),
child: Icon(Icons.add_circle,

234
lib/pages/account_quick.dart

@ -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),
),
),
),
);
}

7
lib/pages/account_restore.dart

@ -119,7 +119,7 @@ class _AccountRestorePageState extends State<AccountRestorePage> { @@ -119,7 +119,7 @@ class _AccountRestorePageState extends State<AccountRestorePage> {
children: <Widget>[
Container(
height: 50.0,
width: 450.0,
width: 600.0,
child: Row(children: [
Expanded(
child: Container(
@ -187,7 +187,7 @@ class _AccountRestorePageState extends State<AccountRestorePage> { @@ -187,7 +187,7 @@ class _AccountRestorePageState extends State<AccountRestorePage> {
),
const SizedBox(height: 16.0),
Container(
width: 450.0,
width: 600.0,
alignment: Alignment.center,
constraints: BoxConstraints(minHeight: 170.0),
padding: const EdgeInsets.all(10.0),
@ -204,7 +204,7 @@ class _AccountRestorePageState extends State<AccountRestorePage> { @@ -204,7 +204,7 @@ class _AccountRestorePageState extends State<AccountRestorePage> {
const SizedBox(height: 16.0),
Container(
height: 50.0,
width: 450.0,
width: 600.0,
child: Row(children: [
Container(
padding: const EdgeInsets.only(right: 8.0),
@ -275,7 +275,6 @@ class _AccountRestorePageState extends State<AccountRestorePage> { @@ -275,7 +275,6 @@ class _AccountRestorePageState extends State<AccountRestorePage> {
])),
const SizedBox(height: 32.0),
ButtonText(
width: 450,
text: lang.next,
enable: _statusChecked,
action: () => _mnemonicRegister(lang.unknown, lang.setPin),

16
lib/pages/setting/profile.dart

@ -268,15 +268,19 @@ class _ProfileDetailState extends State<ProfileDetail> { @@ -268,15 +268,19 @@ class _ProfileDetailState extends State<ProfileDetail> {
}
_pinCheck(String hash, Function callback, String title) {
showShadowDialog(
if (hash.length > 0) {
showShadowDialog(
context,
Icons.security_rounded,
title,
PinWords(
hashPin: hash,
callback: (_key, _hash) async {
Navigator.of(context).pop();
callback();
}));
hashPin: hash,
callback: (_key, _hash) async {
Navigator.of(context).pop();
callback();
}));
} else {
callback();
}
}
}

81
lib/security.dart

@ -9,6 +9,7 @@ import 'package:esse/widgets/shadow_dialog.dart'; @@ -9,6 +9,7 @@ import 'package:esse/widgets/shadow_dialog.dart';
import 'package:esse/widgets/show_pin.dart';
import 'package:esse/pages/account_generate.dart';
import 'package:esse/pages/account_restore.dart';
import 'package:esse/pages/account_quick.dart';
import 'package:esse/utils/logined_cache.dart';
import 'package:esse/utils/better_print.dart';
import 'package:esse/account.dart';
@ -83,8 +84,8 @@ class _SecurityPageState extends State<SecurityPage> { @@ -83,8 +84,8 @@ class _SecurityPageState extends State<SecurityPage> {
children: <Widget>[
SizedBox(height: maxHeight),
Container(
width: 100.0,
height: 100.0,
width: 120.0,
height: 120.0,
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
@ -103,12 +104,26 @@ class _SecurityPageState extends State<SecurityPage> { @@ -103,12 +104,26 @@ class _SecurityPageState extends State<SecurityPage> {
)
),
const SizedBox(height: 40.0),
Text('ESSE', style: TextStyle(fontSize: 20.0)),
const SizedBox(height: 80.0),
Text('ESSE', style: TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold)),
const SizedBox(height: 40.0),
loginForm(color, lang),
const SizedBox(height: 20.0),
ButtonText(width: 450.0, text: lang.ok, enable: _accountsLoaded,
ButtonText(text: lang.ok, enable: _accountsLoaded,
action: () => loginAction(lang.verifyPin)),
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.loginQuick, style: TextStyle(
fontSize: 20.0, color: Color(0xFF6174FF)
))),
),
onTap: () => Navigator.push(context,
MaterialPageRoute(builder: (_) => AccountQuickPage())
),
),
Padding(
padding: const EdgeInsets.only(top: 20),
child: Container(
@ -211,37 +226,45 @@ class _SecurityPageState extends State<SecurityPage> { @@ -211,37 +226,45 @@ class _SecurityPageState extends State<SecurityPage> {
});
}
void loginAction(String title) {
showShadowDialog(
context,
Icons.security_rounded,
title,
PinWords(
hashPin: this._selectedUserLock,
callback: (pinWords, lock) async {
Navigator.of(context).pop();
final res = await httpPost(Global.httpRpc, 'account-login',
[this._selectedUserId, lock]);
void _verifyAfter(String lock) async {
final res = await httpPost(Global.httpRpc, 'account-login',
[this._selectedUserId, lock]);
if (res.isOk) {
final mainAccount = this._accounts[this._selectedUserId]!;
if (res.isOk) {
final mainAccount = this._accounts[this._selectedUserId]!;
Provider.of<AccountProvider>(context, listen: false).updateActivedAccount(mainAccount.gid);
Provider.of<DeviceProvider>(context, listen: false).updateActived();
Provider.of<ChatProvider>(context, listen: false).updateActived();
Provider.of<GroupChatProvider>(context, listen: false).updateActived();
Provider.of<AccountProvider>(context, listen: false).updateActivedAccount(mainAccount.gid);
Provider.of<DeviceProvider>(context, listen: false).updateActived();
Provider.of<ChatProvider>(context, listen: false).updateActived();
Provider.of<GroupChatProvider>(context, listen: false).updateActived();
Navigator.of(context).pushNamedAndRemoveUntil("/", (Route<dynamic> route) => false);
} else {
// TODO tostor error
print(res.error);
}
}
Navigator.of(context).pushNamedAndRemoveUntil("/", (Route<dynamic> route) => false);
} else {
// TODO tostor error
print(res.error);
}
}));
void loginAction(String title) {
if (this._selectedUserLock.length == 0) {
_verifyAfter('');
} else {
showShadowDialog(
context,
Icons.security_rounded,
title,
PinWords(
hashPin: this._selectedUserLock,
callback: (pinWords, lock) async {
Navigator.of(context).pop();
_verifyAfter(lock);
}));
}
}
Widget loginForm(ColorScheme color, AppLocalizations lang) {
return Container(
width: 450.0,
width: 600.0,
height: 50.0,
padding: EdgeInsets.only(left: 20, right: 20),
decoration: BoxDecoration(

12
lib/utils/mnemonic.dart

@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
import 'dart:async';
import 'dart:math';
import 'dart:typed_data';
import 'dart:ui' show Locale;
import 'package:flutter/services.dart' show rootBundle;
@ -66,6 +67,17 @@ extension MnemonicLangExtension on MnemonicLang { @@ -66,6 +67,17 @@ extension MnemonicLangExtension on MnemonicLang {
return MnemonicLang.NONE;
}
}
static MnemonicLang fromLocale(Locale locale) {
switch (locale.languageCode) {
case 'en':
return MnemonicLang.ENGLISH;
case 'zh':
return MnemonicLang.CHINESE_SIMPLIFIED;
default:
return MnemonicLang.ENGLISH;
}
}
}
final _langCache = Map<MnemonicLang, List<String>>();

Loading…
Cancel
Save