Skip to content

Commit ddf7ea3

Browse files
gxhxRomeroYang
authored andcommitted
rebase on develop
1 parent ba51893 commit ddf7ea3

File tree

12 files changed

+1411
-1
lines changed

12 files changed

+1411
-1
lines changed

analysis_options.yaml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# This file configures the analyzer, which statically analyzes Dart code to
2+
# check for errors, warnings, and lints.
3+
#
4+
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
5+
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
6+
# invoked from the command line by running `flutter analyze`.
7+
8+
# The following line activates a set of recommended lints for Flutter apps,
9+
# packages, and plugins designed to encourage good coding practices.
10+
include: package:flutter_lints/flutter.yaml
11+
12+
linter:
13+
# The lint rules applied to this project can be customized in the
14+
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
15+
# included above or to enable additional rules. A list of all available lints
16+
# and their documentation is published at
17+
# https://dart-lang.github.io/linter/lints/index.html.
18+
#
19+
# Instead of disabling a lint rule for the entire project in the
20+
# section below, it can also be suppressed for a single line of code
21+
# or a specific dart file by using the `// ignore: name_of_lint` and
22+
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
23+
# producing the lint.
24+
rules:
25+
# avoid_print: false # Uncomment to disable the `avoid_print` rule
26+
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
27+
28+
# Additional information about this file can be found at
29+
# https://dart.dev/guides/language/analysis-options

assets/images/icon_bridge_swap.png

3.13 KB
Loading

assets/images/public/hub_bridge.png

198 KB
Loading

lib/app.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import 'package:app/pages/assets/asset/locksDetailPage.dart';
1212
import 'package:app/pages/assets/manage/manageAssetsPage.dart';
1313
import 'package:app/pages/assets/transfer/detailPage.dart';
1414
import 'package:app/pages/assets/transfer/transferPage.dart';
15+
import 'package:app/pages/bridge/bridgePage.dart';
1516
import 'package:app/pages/bridgeTestPage.dart';
1617
import 'package:app/pages/browser/browserPage.dart';
1718
import 'package:app/pages/browser/dappLatestPage.dart';
@@ -758,6 +759,9 @@ class _WalletAppState extends State<WalletApp> with WidgetsBindingObserver {
758759
CompletedPage.route: (_) => CompletedPage(_service),
759760
EcosystemPage.route: (_) => EcosystemPage(_service),
760761

762+
//bridge
763+
BridgePage.route: (_) => BridgePage(_service),
764+
761765
/// test
762766
DAppsTestPage.route: (_) => DAppsTestPage(),
763767
BridgeTestPage.route: (_) => BridgeTestPage(_service.plugin.sdk)
Lines changed: 305 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,305 @@
1+
import 'package:app/pages/ecosystem/converToPage.dart';
2+
import 'package:flutter/material.dart';
3+
import 'package:flutter_svg/svg.dart';
4+
import 'package:polkawallet_sdk/api/api.dart';
5+
import 'package:polkawallet_sdk/storage/types/keyPairData.dart';
6+
import 'package:polkawallet_sdk/utils/i18n.dart';
7+
import 'package:polkawallet_ui/components/v3/plugin/pluginTextTag.dart';
8+
import 'package:polkawallet_ui/pages/v3/accountListPage.dart';
9+
import 'package:polkawallet_ui/utils/format.dart';
10+
import 'package:polkawallet_ui/utils/i18n.dart';
11+
import 'package:polkawallet_ui/utils/index.dart';
12+
import 'package:polkawallet_ui/components/addressIcon.dart';
13+
14+
class BridgeAddressTextFormField extends StatefulWidget {
15+
const BridgeAddressTextFormField(this.api, this.localAccounts,
16+
{this.initialValue,
17+
this.onChanged,
18+
this.hintText,
19+
this.hintStyle,
20+
this.errorStyle,
21+
this.tag,
22+
this.onFocusChange,
23+
this.isClean = false,
24+
Key key})
25+
: super(key: key);
26+
final PolkawalletApi api;
27+
final List<KeyPairData> localAccounts;
28+
final KeyPairData initialValue;
29+
final Function(KeyPairData) onChanged;
30+
31+
final String hintText;
32+
final TextStyle hintStyle;
33+
final TextStyle errorStyle;
34+
final String tag;
35+
36+
final void Function(bool) onFocusChange;
37+
final bool isClean;
38+
39+
@override
40+
createState() => _BridgeAddressTextFormFieldState();
41+
}
42+
43+
class _BridgeAddressTextFormFieldState
44+
extends State<BridgeAddressTextFormField> {
45+
final TextEditingController _controller = TextEditingController();
46+
final Map _addressIndexMap = {};
47+
final Map _addressIconsMap = {};
48+
String validatorError;
49+
bool hasFocus = false;
50+
final FocusNode _commentFocus = FocusNode();
51+
52+
Future<KeyPairData> _getAccountFromInput(String input) async {
53+
// return local account list if input empty
54+
if (input.isEmpty || input.trim().length < 3) {
55+
return null;
56+
}
57+
58+
// check if user input is valid address or indices
59+
final checkAddress = await widget.api.account.decodeAddress([input]);
60+
if (checkAddress == null) {
61+
return null;
62+
}
63+
64+
final acc = KeyPairData();
65+
acc.address = input;
66+
acc.pubKey = checkAddress.keys.toList()[0];
67+
if (input.length < 47) {
68+
// check if input indices in local account list
69+
final int indicesIndex = widget.localAccounts.indexWhere((e) {
70+
final Map accInfo = e.indexInfo;
71+
return accInfo != null && accInfo['accountIndex'] == input;
72+
});
73+
if (indicesIndex >= 0) {
74+
return widget.localAccounts[indicesIndex];
75+
}
76+
// query account address with account indices
77+
final queryRes =
78+
await widget.api.account.queryAddressWithAccountIndex(input);
79+
if (queryRes != null) {
80+
acc.address = queryRes;
81+
acc.name = input;
82+
}
83+
} else {
84+
// check if input address in local account list
85+
final int addressIndex = widget.localAccounts
86+
.indexWhere((e) => _itemAsString(e).contains(input));
87+
if (addressIndex >= 0) {
88+
return widget.localAccounts[addressIndex];
89+
}
90+
}
91+
92+
// fetch address info if it's a new address
93+
final res = await widget.api.account.getAddressIcons([acc.address]);
94+
if (res != null) {
95+
if (res.isNotEmpty) {
96+
acc.icon = res[0][1];
97+
setState(() {
98+
_addressIconsMap.addAll({acc.address: res[0][1]});
99+
});
100+
}
101+
102+
// The indices query too slow, so we use address as account name
103+
acc.name ??= Fmt.address(acc.address);
104+
}
105+
return acc;
106+
}
107+
108+
String _itemAsString(KeyPairData item) {
109+
final Map accInfo = _getAddressInfo(item);
110+
String idx = '';
111+
if (accInfo != null && accInfo['accountIndex'] != null) {
112+
idx = accInfo['accountIndex'];
113+
}
114+
if (item.name != null) {
115+
return '${item.name} $idx ${item.address}';
116+
}
117+
return '${UI.accountDisplayNameString(item.address, accInfo)} $idx ${item.address}';
118+
}
119+
120+
Map _getAddressInfo(KeyPairData acc) {
121+
return acc.indexInfo ?? _addressIndexMap[acc.address];
122+
}
123+
124+
@override
125+
Widget build(BuildContext context) {
126+
final dic = I18n.of(context).getDic(i18n_full_dic_ui, 'common');
127+
128+
return Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
129+
widget.tag != null ? PluginTextTag(title: widget.tag) : Container(),
130+
Focus(
131+
onFocusChange: (hasFocus) async {
132+
if (!hasFocus) {
133+
if (_controller.text.trim().isNotEmpty) {
134+
final data = await _getAccountFromInput(_controller.text);
135+
setState(() {
136+
validatorError = data == null ? dic['address.error'] : null;
137+
});
138+
if (data != null && widget.onChanged != null) {
139+
widget.onChanged(data);
140+
}
141+
}
142+
setState(() {
143+
this.hasFocus = hasFocus;
144+
});
145+
if (widget.onFocusChange != null) {
146+
widget.onFocusChange(hasFocus);
147+
}
148+
}
149+
},
150+
child: !hasFocus &&
151+
widget.initialValue != null &&
152+
validatorError == null
153+
? Stack(
154+
alignment: Alignment.centerRight,
155+
children: [
156+
Container(
157+
width: double.infinity,
158+
padding: const EdgeInsets.only(left: 8),
159+
height: 48,
160+
decoration: const BoxDecoration(
161+
color: Color(0x24FFFFFF),
162+
borderRadius: BorderRadius.only(
163+
topLeft: Radius.circular(0),
164+
bottomLeft: Radius.circular(4),
165+
topRight: Radius.circular(4),
166+
bottomRight: Radius.circular(4))),
167+
child: Row(
168+
children: [
169+
Container(
170+
margin: const EdgeInsets.only(right: 8),
171+
child: AddressIcon(
172+
widget.initialValue.address,
173+
svg: widget.initialValue.icon,
174+
size: 30,
175+
tapToCopy: false,
176+
),
177+
),
178+
Expanded(
179+
child: Column(
180+
mainAxisAlignment: MainAxisAlignment.center,
181+
crossAxisAlignment: CrossAxisAlignment.start,
182+
children: <Widget>[
183+
Text(
184+
UI.accountName(context, widget.initialValue),
185+
style: Theme.of(context)
186+
.textTheme
187+
.headline4
188+
?.copyWith(
189+
fontFamily: 'Titillium Web SemiBold',
190+
fontSize: UI.getTextSize(14, context),
191+
fontWeight: FontWeight.w600,
192+
color: const Color(0xFFFFFFFF)),
193+
),
194+
Text(
195+
Fmt.address(widget.initialValue.address),
196+
style: TextStyle(
197+
fontFamily: 'Titillium Web Regular',
198+
fontSize: UI.getTextSize(10, context),
199+
color: const Color(0xFFFFFFFF)),
200+
)
201+
],
202+
),
203+
),
204+
GestureDetector(
205+
child: const Padding(
206+
padding: EdgeInsets.only(right: 8),
207+
child: Icon(
208+
Icons.close,
209+
size: 18,
210+
color: Colors.white,
211+
)),
212+
onTap: () {
213+
setState(() {
214+
hasFocus = true;
215+
});
216+
Future.delayed(const Duration(milliseconds: 100),
217+
() {
218+
FocusScope.of(context)
219+
.requestFocus(_commentFocus);
220+
});
221+
if (widget.onFocusChange != null) {
222+
widget.onFocusChange(hasFocus);
223+
}
224+
},
225+
)
226+
],
227+
)),
228+
],
229+
)
230+
: Stack(
231+
children: [
232+
Container(
233+
decoration: const BoxDecoration(
234+
color: Color(0x24FFFFFF),
235+
borderRadius: BorderRadius.only(
236+
bottomLeft: Radius.circular(4),
237+
topRight: Radius.circular(4),
238+
bottomRight: Radius.circular(4))),
239+
child: TextField(
240+
controller: _controller,
241+
focusNode: _commentFocus,
242+
onChanged: (value) {
243+
if (validatorError != null &&
244+
_controller.text.trim().toString().isEmpty) {
245+
setState(() {
246+
validatorError = null;
247+
});
248+
}
249+
},
250+
style: const TextStyle(color: Colors.white),
251+
cursorColor: Colors.white,
252+
maxLines: 1,
253+
decoration: InputDecoration(
254+
contentPadding:
255+
const EdgeInsets.only(left: 16, right: 8),
256+
hintText: widget.hintText,
257+
hintStyle: widget.hintStyle,
258+
focusedBorder: const OutlineInputBorder(
259+
borderSide:
260+
BorderSide(color: Color(0xFFFF7849), width: 2)),
261+
border: InputBorder.none,
262+
// suffix:
263+
),
264+
),
265+
),
266+
Align(
267+
alignment: Alignment.centerRight,
268+
child: GestureDetector(
269+
onTap: () async {
270+
_controller.clear();
271+
setState(() {
272+
hasFocus = false;
273+
});
274+
Future.delayed(const Duration(milliseconds: 100), () {
275+
FocusScope.of(context).unfocus;
276+
});
277+
var res = await Navigator.of(context).pushNamed(
278+
AccountListPage.route,
279+
arguments:
280+
AccountListPageParams(list: widget.localAccounts),
281+
);
282+
if (res != null && widget.onChanged != null) {
283+
widget.onChanged(res as KeyPairData);
284+
}
285+
},
286+
child: SizedBox(
287+
height: 48,
288+
child: Padding(
289+
padding: const EdgeInsets.only(right: 8),
290+
child: SvgPicture.asset(
291+
"packages/polkawallet_ui/assets/images/icon_user.svg",
292+
height: 24,
293+
color: Colors.white,
294+
),
295+
),
296+
),
297+
),
298+
),
299+
],
300+
),
301+
),
302+
ErrorMessage(validatorError)
303+
]);
304+
}
305+
}

0 commit comments

Comments
 (0)