Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
ginkgo
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package Registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Fred
ginkgo
Commits
5599fdca
Commit
5599fdca
authored
1 year ago
by
vjrj
Browse files
Options
Downloads
Patches
Plain Diff
Cesium plus username support (wip)
parent
7a4a41b2
No related branches found
No related tags found
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
lib/g1/api.dart
+111
-96
111 additions, 96 deletions
lib/g1/api.dart
lib/ui/widgets/first_screen/card_name_editable.dart
+129
-20
129 additions, 20 deletions
lib/ui/widgets/first_screen/card_name_editable.dart
with
240 additions
and
116 deletions
lib/g1/api.dart
+
111
−
96
View file @
5599fdca
...
...
@@ -31,7 +31,7 @@ final String currency = currencyDotEnv.isEmpty ? 'g1' : currencyDotEnv;
Future
<
String
>
getTxHistory
(
String
publicKey
)
async
{
final
Response
response
=
await
requestWithRetry
(
NodeType
.
duniter
,
'/tx/history/
$publicKey
'
);
await
requestWithRetry
(
NodeType
.
duniter
,
'/tx/history/
$publicKey
'
);
if
(
response
.
statusCode
==
200
)
{
return
response
.
body
;
}
else
{
...
...
@@ -59,7 +59,7 @@ Future<Response> searchCPlusUser(String searchTerm) async {
'/user/profile/_search?q=title:
$searchTermLower
OR issuer:
$searchTerm
OR title:
$searchTermCapitalized
OR title:
$searchTerm
'
;
final
Response
response
=
await
requestCPlusWithRetry
(
query
,
retryWith404:
false
);
await
requestCPlusWithRetry
(
query
,
retryWith404:
false
);
return
response
;
}
...
...
@@ -71,12 +71,12 @@ Future<Contact> getProfile(String pubKeyRaw,
'/user/profile/
$pubKey
'
,
retryWith404:
false
);
final
Map
<
String
,
dynamic
>
result
=
const
JsonDecoder
()
.
convert
(
cPlusResponse
.
body
)
as
Map
<
String
,
dynamic
>;
const
JsonDecoder
()
.
convert
(
cPlusResponse
.
body
)
as
Map
<
String
,
dynamic
>;
if
(
result
[
'found'
]
==
false
)
{
return
Contact
(
pubKey:
pubKey
);
}
final
Map
<
String
,
dynamic
>
profile
=
const
JsonDecoder
()
.
convert
(
cPlusResponse
.
body
)
as
Map
<
String
,
dynamic
>;
const
JsonDecoder
()
.
convert
(
cPlusResponse
.
body
)
as
Map
<
String
,
dynamic
>;
final
Contact
c
=
await
contactFromResultSearch
(
profile
);
if
(
!
onlyCPlusProfile
)
{
// This penalize the gva rate limit
...
...
@@ -117,7 +117,7 @@ Future<List<Contact>> searchWot(String searchTermRaw) async {
final
List
<
Contact
>
contacts
=
<
Contact
>[];
if
(
response
.
statusCode
==
HttpStatus
.
ok
)
{
final
Map
<
String
,
dynamic
>
data
=
json
.
decode
(
response
.
body
)
as
Map
<
String
,
dynamic
>;
json
.
decode
(
response
.
body
)
as
Map
<
String
,
dynamic
>;
final
List
<
dynamic
>
results
=
data
[
'results'
]
as
List
<
dynamic
>;
// logger('Returning wot results ${results.length}');
if
(
results
.
isNotEmpty
)
{
...
...
@@ -144,11 +144,11 @@ Future<Contact> getWot(Contact contact) async {
// Will be better to analyze the 404 response (to detect faulty node)
if
(
response
.
statusCode
==
HttpStatus
.
ok
)
{
final
Map
<
String
,
dynamic
>
data
=
json
.
decode
(
response
.
body
)
as
Map
<
String
,
dynamic
>;
json
.
decode
(
response
.
body
)
as
Map
<
String
,
dynamic
>;
final
List
<
dynamic
>
results
=
data
[
'results'
]
as
List
<
dynamic
>;
if
(
results
.
isNotEmpty
)
{
final
List
<
dynamic
>
uids
=
(
results
[
0
]
as
Map
<
String
,
dynamic
>)[
'uids'
]
as
List
<
dynamic
>;
(
results
[
0
]
as
Map
<
String
,
dynamic
>)[
'uids'
]
as
List
<
dynamic
>;
if
(
uids
.
isNotEmpty
)
{
// ignore: avoid_dynamic_calls
return
contact
.
copyWith
(
nick:
uids
[
0
]
!
[
'uid'
]
as
String
);
...
...
@@ -161,14 +161,14 @@ Future<Contact> getWot(Contact contact) async {
@Deprecated
(
'use getProfile'
)
Future
<
String
>
_getDataImageFromKey
(
String
publicKey
)
async
{
final
Response
response
=
await
requestCPlusWithRetry
(
'/user/profile/
$publicKey
'
);
await
requestCPlusWithRetry
(
'/user/profile/
$publicKey
'
);
if
(
response
.
statusCode
==
HttpStatus
.
ok
)
{
final
Map
<
String
,
dynamic
>
data
=
json
.
decode
(
response
.
body
)
as
Map
<
String
,
dynamic
>;
json
.
decode
(
response
.
body
)
as
Map
<
String
,
dynamic
>;
final
Map
<
String
,
dynamic
>
source
=
data
[
'_source'
]
as
Map
<
String
,
dynamic
>
;
if
(
source
.
containsKey
(
'avatar'
))
{
final
Map
<
String
,
dynamic
>
avatarData
=
source
[
'avatar'
]
as
Map
<
String
,
dynamic
>
;
source
[
'avatar'
]
as
Map
<
String
,
dynamic
>
;
if
(
avatarData
.
containsKey
(
'_content'
))
{
final
String
content
=
avatarData
[
'_content'
]
as
String
;
return
'data:image/png;base64,
$content
'
;
...
...
@@ -263,18 +263,16 @@ Future<void> _fetchGvaNodes({bool force = false}) async {
NodeManager
()
.
loading
=
false
;
}
int
nodesWorking
(
NodeType
type
)
=
>
NodeManager
()
.
nodeList
(
type
)
.
where
((
Node
n
)
=
>
n
.
errors
<
NodeManager
.
maxNodeErrors
)
.
toList
()
.
length
;
int
nodesWorking
(
NodeType
type
)
=
>
NodeManager
()
.
nodeList
(
type
)
.
where
((
Node
n
)
=
>
n
.
errors
<
NodeManager
.
maxNodeErrors
)
.
toList
()
.
length
;
List
<
Node
>
nodesWorkingList
(
NodeType
type
)
=
>
NodeManager
()
.
nodeList
(
type
)
.
where
((
Node
n
)
=
>
n
.
errors
<
NodeManager
.
maxNodeErrors
)
.
toList
();
List
<
Node
>
nodesWorkingList
(
NodeType
type
)
=
>
NodeManager
()
.
nodeList
(
type
)
.
where
((
Node
n
)
=
>
n
.
errors
<
NodeManager
.
maxNodeErrors
)
.
toList
();
Future
<
List
<
Node
>>
_fetchDuniterNodesFromPeers
(
NodeType
type
)
async
{
final
List
<
Node
>
lNodes
=
<
Node
>[];
...
...
@@ -286,14 +284,14 @@ Future<List<Node>> _fetchDuniterNodesFromPeers(NodeType type) async {
final
Response
response
=
await
getPeers
();
if
(
response
.
statusCode
==
200
)
{
final
Map
<
String
,
dynamic
>
peerList
=
jsonDecode
(
response
.
body
)
as
Map
<
String
,
dynamic
>;
jsonDecode
(
response
.
body
)
as
Map
<
String
,
dynamic
>;
final
List
<
dynamic
>
peers
=
(
peerList
[
'peers'
]
as
List
<
dynamic
>)
.
where
((
dynamic
peer
)
=
>
(
peer
as
Map
<
String
,
dynamic
>)[
'currency'
]
==
currency
)
(
peer
as
Map
<
String
,
dynamic
>)[
'currency'
]
==
currency
)
.
where
(
(
dynamic
peer
)
=
>
(
peer
as
Map
<
String
,
dynamic
>)[
'version'
]
==
10
)
.
where
((
dynamic
peer
)
=
>
(
peer
as
Map
<
String
,
dynamic
>)[
'status'
]
==
'UP'
)
(
peer
as
Map
<
String
,
dynamic
>)[
'status'
]
==
'UP'
)
.
toList
();
// reorder peer list
peers
.
shuffle
();
...
...
@@ -301,7 +299,7 @@ Future<List<Node>> _fetchDuniterNodesFromPeers(NodeType type) async {
final
Map
<
String
,
dynamic
>
peer
=
peerR
as
Map
<
String
,
dynamic
>;
if
(
peer
[
'endpoints'
]
!=
null
)
{
final
List
<
String
>
endpoints
=
List
<
String
>
.
from
(
peer
[
'endpoints'
]
as
List
<
dynamic
>);
List
<
String
>
.
from
(
peer
[
'endpoints'
]
as
List
<
dynamic
>);
for
(
int
j
=
0
;
j
<
endpoints
.
length
;
j
++
)
{
if
(
endpoints
[
j
]
.
startsWith
(
apyType
))
{
final
String
endpointUnParsed
=
endpoints
[
j
];
...
...
@@ -313,9 +311,7 @@ Future<List<Node>> _fetchDuniterNodesFromPeers(NodeType type) async {
final
NodeCheck
nodeCheck
=
await
_pingNode
(
endpoint
,
type
);
final
Duration
latency
=
nodeCheck
.
latency
;
logger
(
'Evaluating node:
$endpoint
, latency
${latency
.inMicroseconds}
currentBlock:
${nodeCheck
.currentBlock}
'
);
'Evaluating node:
$endpoint
, latency
${latency.inMicroseconds}
currentBlock:
${nodeCheck.currentBlock}
'
);
final
Node
node
=
Node
(
url:
endpoint
,
latency:
latency
.
inMicroseconds
,
...
...
@@ -348,8 +344,7 @@ Future<List<Node>> _fetchDuniterNodesFromPeers(NodeType type) async {
}
}
logger
(
'Fetched
${lNodes.length}
${type.name}
nodes ordered by latency
${lNodes
.isNotEmpty ? '(first: ${lNodes.first.url}
)'
:
'(zero nodes)'
}
');
'Fetched
${lNodes.length}
${type.name}
nodes ordered by latency
${lNodes.isNotEmpty ? '(first: ${lNodes.first.url}
)'
:
'(zero nodes)'
}
');
} catch (e, stacktrace) {
await Sentry.captureException(e, stackTrace: stacktrace);
logger('
General
error
in
fetch
$
{
type
.
name
}
nodes:
$e
');
...
...
@@ -401,8 +396,7 @@ Future<List<Node>> _fetchNodes(NodeType type) async {
}
logger(
'
Fetched
$
{
lNodes
.
length
}
$
{
type
.
name
}
nodes
ordered
by
latency
(
first:
$
{
lNodes
.
first
.
url
})
');
'
Fetched
$
{
lNodes
.
length
}
$
{
type
.
name
}
nodes
ordered
by
latency
(
first:
$
{
lNodes
.
first
.
url
})
');
} catch (e, stacktrace) {
await Sentry.captureException(e, stackTrace: stacktrace);
logger('
General
error
in
fetch
$
{
type
.
name
}
:
$e
');
...
...
@@ -419,8 +413,7 @@ Future<NodeCheck> _pingNode(String node, NodeType type) async {
int currentBlock = 0;
Duration latency;
try {
final Stopwatch stopwatch = Stopwatch()
..start();
final Stopwatch stopwatch = Stopwatch()..start();
if (type == NodeType.duniter) {
final Response response = await http
.get(Uri.parse('
$node
/
blockchain
/
current
'))
...
...
@@ -429,7 +422,7 @@ Future<NodeCheck> _pingNode(String node, NodeType type) async {
latency = stopwatch.elapsed;
if (response.statusCode == 200) {
final Map<String, dynamic> json =
jsonDecode(response.body) as Map<String, dynamic>;
jsonDecode(response.body) as Map<String, dynamic>;
currentBlock = json['
number
'] as int;
} else {
latency = wrongNodeDuration;
...
...
@@ -438,7 +431,7 @@ Future<NodeCheck> _pingNode(String node, NodeType type) async {
// see: http://g1.data.e-is.pro/network/peering
await http
.get(Uri.parse('
$node
/
network
/
peering
'))
// Decrease http timeout during ping
// Decrease http timeout during ping
.timeout(timeout);
stopwatch.stop();
latency = stopwatch.elapsed;
...
...
@@ -454,8 +447,7 @@ Future<NodeCheck> _pingNode(String node, NodeType type) async {
latency = balance >= 0 ? stopwatch.elapsed : wrongNodeDuration;
}
logger(
'
Ping
tested
in
node
$node
(
$type
),
latency
$
{
latency
.
inMicroseconds
},
current
block
$currentBlock
');
'
Ping
tested
in
node
$node
(
$type
),
latency
$
{
latency
.
inMicroseconds
},
current
block
$currentBlock
');
return NodeCheck(latency: latency, currentBlock: currentBlock);
} catch (e) {
// Handle exception when node is unavailable etc
...
...
@@ -481,20 +473,22 @@ Future<http.Response> requestCPlusWithRetry(String path,
Future<http.Response> requestGvaWithRetry(String path,
{bool retryWith404 = true,
bool isGet = true
,
Map<String, String>? headers,
Object? body,
Encoding? encoding}) async {
HttpType httpType = HttpType.get
,
Map<String, String>? headers,
Object? body,
Encoding? encoding}) async {
return _requestWithRetry(NodeType.gva, path, true, retryWith404,
isGet: isGet
, headers: headers, body: body, encoding: encoding);
httpType: httpType
, headers: headers, body: body, encoding: encoding);
}
Future<http.Response> _requestWithRetry(NodeType type, String path,
bool dontRecord, bool retryWith404,
{bool isGet = true,
Map<String, String>? headers,
Object? body,
Encoding? encoding}) async {
enum HttpType { get, post, delete }
Future<http.Response> _requestWithRetry(
NodeType type, String path, bool dontRecord, bool retryWith404,
{HttpType httpType = HttpType.get,
Map<String, String>? headers,
Object? body,
Encoding? encoding}) async {
final List<Node> nodes = NodeManager()
.nodeList(type)
.where((Node node) => node.errors <= NodeManager.maxNodeErrors)
...
...
@@ -503,8 +497,8 @@ Future<http.Response> _requestWithRetry(NodeType type, String path,
nodes.addAll(type == NodeType.duniter
? defaultDuniterNodes
: type == NodeType.cesiumPlus
? defaultCesiumPlusNodes
: defaultGvaNodes);
? defaultCesiumPlusNodes
: defaultGvaNodes);
}
for (final int timeout in <int>[10]) {
// only one timeout for now
...
...
@@ -513,17 +507,16 @@ Future<http.Response> _requestWithRetry(NodeType type, String path,
try {
final Uri url = Uri.parse('
$
{
node
.
url
}
$path
');
logger('
Fetching
$url
(
$
{
type
.
name
})
');
final int startTime = DateTime
.now()
.millisecondsSinceEpoch;
final Response response = isGet
final int startTime = DateTime.now().millisecondsSinceEpoch;
final Response response = httpType == HttpType.get
? await http.get(url).timeout(Duration(seconds: timeout))
: await http
.post(url, body: body, headers: headers, encoding: encoding)
.timeout(Duration(seconds: timeout));
final int endTime = DateTime
.now()
.millisecondsSinceEpoch;
: httpType == HttpType.post
? await http
.post(url, body: body, headers: headers, encoding: encoding)
.timeout(Duration(seconds: timeout))
: await http.delete(url,
body: body, headers: headers, encoding: encoding);
final int endTime = DateTime.now().millisecondsSinceEpoch;
final int newLatency = endTime - startTime;
if (!kReleaseMode) {
logger('
response
.
statusCode
:
$
{
response
.
statusCode
}
');
...
...
@@ -568,10 +561,11 @@ Future<http.Response> _requestWithRetry(NodeType type, String path,
'
Cannot
make
the
request
to
any
of
the
$
{
nodes
.
length
}
nodes
');
}
Future<PayResult> pay({required String to,
required double amount,
String? comment,
bool? useMempool}) async {
Future<PayResult> pay(
{required String to,
required double amount,
String? comment,
bool? useMempool}) async {
try {
final SelectedGvaNode selected = getGvaNode();
...
...
@@ -580,8 +574,7 @@ Future<PayResult> pay({required String to,
final Gva gva = Gva(node: nodeUrl);
final CesiumWallet wallet = await SharedPreferencesHelper().getWallet();
logger(
'
Trying
$nodeUrl
to
send
$amount
to
$to
with
comment
$
{
comment
??
''
}
');
'
Trying
$nodeUrl
to
send
$amount
to
$to
with
comment
$
{
comment
??
''
}
');
final String response = await gva.pay(
recipient: extractPublicKey(to),
...
...
@@ -641,9 +634,7 @@ class PayResult {
String
proxyfyNode
(
String
nodeUrl
)
{
final
String
url
=
inProduction
&&
kIsWeb
?
'
${window.location.protocol}
//
${window.location
.hostname}
/proxy/
${nodeUrl.replaceFirst('https://', '').replaceFirst(
'http://', '')}
/'
?
'
${window.location.protocol}
//
${window.location.hostname}
/proxy/
${nodeUrl.replaceFirst('https://', '').replaceFirst('http://', '')}
/'
:
nodeUrl
;
return
url
;
}
...
...
@@ -651,7 +642,7 @@ String proxyfyNode(String nodeUrl) {
Future
<
Tuple2
<
Map
<
String
,
dynamic
>
?
,
Node
>>
gvaHistoryAndBalance
(
String
pubKeyRaw
,
[
int
?
pageSize
,
String
?
cursor
])
async
{
String
?
cursor
])
async
{
logger
(
'Get tx history (page size:
$pageSize
: cursor
$cursor
)'
);
final
String
pubKey
=
extractPublicKey
(
pubKeyRaw
);
return
gvaFunctionWrapper
<
Map
<
String
,
dynamic
>>(
...
...
@@ -668,8 +659,8 @@ Future<Tuple2<String?, Node>> gvaNick(String pubKey) async {
pubKey
,
(
Gva
gva
)
=
>
gva
.
getUsername
(
extractPublicKey
(
pubKey
)));
}
Future
<
Tuple2
<
T
?
,
Node
>>
gvaFunctionWrapper
<
T
>(
String
pubKey
,
Future
<
T
?
>
Function
(
Gva
)
specificFunction
)
async
{
Future
<
Tuple2
<
T
?
,
Node
>>
gvaFunctionWrapper
<
T
>(
String
pubKey
,
Future
<
T
?
>
Function
(
Gva
)
specificFunction
)
async
{
final
List
<
Node
>
nodes
=
_getBestGvaNodes
();
for
(
int
i
=
0
;
i
<
nodes
.
length
;
i
++
)
{
final
Node
node
=
nodes
[
i
];
...
...
@@ -700,8 +691,8 @@ List<Node> _getBestGvaNodes() {
.
toList
();
final
int
maxCurrentBlock
=
fnodes
.
fold
(
0
,
(
int
max
,
Node
node
)
=
>
node
.
currentBlock
>
max
?
node
.
currentBlock
:
max
);
(
int
max
,
Node
node
)
=
>
node
.
currentBlock
>
max
?
node
.
currentBlock
:
max
);
final
List
<
Node
>
nodes
=
fnodes
.
where
((
Node
node
)
=
>
node
.
currentBlock
==
maxCurrentBlock
)
.
toList
();
...
...
@@ -729,24 +720,25 @@ void increaseNodeErrors(NodeType type, Node node) {
// http://doc.e-is.pro/cesium-plus-pod/REST_API.html#userprofile
// https://git.p2p.legal/axiom-team/jaklis/src/branch/master/lib/cesiumCommon.py
// Get an profile, by public key: user/profile/<pubkey>
// Add a new profile: user/profile (POST)
// Update an existing profile: user/profile/_update (POST)
// Delete an existing profile: user/profile/_delete (DELETE?)
Future
<
void
>
createOrUpdateCesiumPlusUser
(
String
name
)
async
{
final
CesiumWallet
wallet
=
await
SharedPreferencesHelper
()
.
getWallet
();
// Define the endpoints
final
String
pubKey
=
wallet
.
pubkey
;
// Make the HTTP GET request to check if the user exists
final
http
.
Response
getResponse
=
await
_requestWithRetry
(
NodeType
.
cesiumPlus
,
'/api/user/profile/
$pubKey
'
,
false
,
false
);
// Check if the user exists
final
String
?
userName
=
await
getCesiumPlusUser
(
pubKey
);
// Prepare the user profile data
final
Map
<
String
,
dynamic
>
userProfile
=
<
String
,
dynamic
>{
'version'
:
2
,
'issuer'
:
pubKey
,
'title'
:
name
+
userNameSuffix
,
'time'
:
DateTime
.
now
()
.
millisecondsSinceEpoch
~/
'time'
:
DateTime
.
now
()
.
millisecondsSinceEpoch
~/
1000
,
// current time in seconds
'tags'
:
<
String
>[],
};
final
String
userProfileJson
=
jsonEncode
(
userProfile
);
...
...
@@ -762,25 +754,25 @@ Future<void> createOrUpdateCesiumPlusUser(String name) async {
'Content-Type'
:
'application/json'
,
};
if
(
getResponse
.
statusCod
e
=
=
200
)
{
if
(
userNam
e
!
=
null
)
{
// User exists, update the user profile
final
http
.
Response
updateResponse
=
await
_requestWithRetry
(
NodeType
.
cesiumPlus
,
'/
api/
user/profile/_update'
,
false
,
fals
e
,
isGet:
false
,
NodeType
.
cesiumPlus
,
'/user/profile/_update'
,
false
,
tru
e
,
httpType:
HttpType
.
post
,
headers:
headers
,
body:
userProfileJsonWithHashAndSignature
);
if
(
updateResponse
.
statusCode
==
200
)
{
logger
(
'User profile updated successfully.'
);
}
else
{
logger
(
'Failed to update user profile. Status code:
${updateResponse
.statusCode
}
'
);
'Failed to update user profile. Status code:
${updateResponse
.statusCode}
'
);
logger
(
'Response body:
${updateResponse.body
}
'
);
}
}
else
if
(
getResponse
.
statusCod
e
==
404
)
{
}
else
if
(
userNam
e
==
null
)
{
// User does not exist, create a new user profile
final
http
.
Response
createResponse
=
await
_requestWithRetry
(
NodeType
.
cesiumPlus
,
'/
api/
user/profile'
,
false
,
false
,
isGet:
false
,
NodeType
.
cesiumPlus
,
'/user/profile'
,
false
,
false
,
httpType:
HttpType
.
post
,
headers:
headers
,
body:
userProfileJsonWithHashAndSignature
);
...
...
@@ -788,16 +780,39 @@ Future<void> createOrUpdateCesiumPlusUser(String name) async {
logger
(
'User profile created successfully.'
);
}
else
{
logger
(
'Failed to create user profile. Status code:
${createResponse
.statusCode}
'
);
'Failed to create user profile. Status code:
${createResponse.statusCode}
'
);
}
}
else
{
logger
(
'Failed to check if user exists. Status code:
${getResponse
.statusCode}
'
);
}
}
Future
<
String
?
>
getCesiumPlusUser
(
String
pubKey
)
async
{
final
Contact
c
=
await
getProfile
(
pubKey
,
true
);
return
c
.
name
;
}
Future
<
bool
>
deleteCesiumPlusUser
()
async
{
final
CesiumWallet
wallet
=
await
SharedPreferencesHelper
()
.
getWallet
();
final
String
pubKey
=
wallet
.
pubkey
;
final
Map
<
String
,
dynamic
>
userProfile
=
<
String
,
dynamic
>{
'version'
:
2
,
'id'
:
pubKey
,
'issuer'
:
pubKey
,
'index'
:
'user'
,
'type'
:
'profile'
,
'time'
:
DateTime
.
now
()
.
millisecondsSinceEpoch
~/
1000
,
// current time in seconds
};
final
String
userProfileJson
=
jsonEncode
(
userProfile
);
final
String
signature
=
wallet
.
sign
(
userProfileJson
);
userProfile
[
'hash'
]
=
calculateHash
(
userProfileJson
);
userProfile
[
'signature'
]
=
signature
;
final
http
.
Response
delResponse
=
await
_requestWithRetry
(
NodeType
.
cesiumPlus
,
'/user/profile/_delete'
,
false
,
false
,
httpType:
HttpType
.
post
);
return
delResponse
.
statusCode
==
200
;
}
String
calculateHash
(
String
input
)
{
final
List
<
int
>
bytes
=
utf8
.
encode
(
input
);
// data being hashed
...
...
This diff is collapsed.
Click to expand it.
lib/ui/widgets/first_screen/card_name_editable.dart
+
129
−
20
View file @
5599fdca
import
'package:easy_localization/easy_localization.dart'
;
import
'package:flutter/material.dart'
;
import
'../../../g1/api.dart'
;
import
'../../../shared_prefs.dart'
;
import
'../../logger.dart'
;
import
'../../ui_helpers.dart'
;
...
...
@@ -15,22 +16,48 @@ class CardNameEditable extends StatefulWidget {
class
_CardNameEditableState
extends
State
<
CardNameEditable
>
{
bool
_isEditingText
=
false
;
late
TextEditingController
_editingController
;
final
TextEditingController
_editingController
=
TextEditingController
()
;
late
String
currentText
;
late
String
defValue
;
late
String
name
;
// late FocusNode myFocusNode;
final
String
pubKey
=
SharedPreferencesHelper
()
.
getPubKey
();
String
_previousValue
=
''
;
@override
void
initState
()
{
super
.
initState
();
defValue
=
tr
(
'your_name_here'
);
name
=
SharedPreferencesHelper
()
.
getName
()
;
currentText
=
_currentTextOrDef
();
_
editingController
=
TextEditingController
(
text:
currentText
);
currentText
=
defValue
;
// myFocusNode = FocusNode
();
_
initValue
(
);
}
String
_currentTextOrDef
()
=
>
(
name
==
tr
(
'g1_wallet'
)
||
name
.
isEmpty
)
?
defValue
:
name
;
Future
<
void
>
_initValue
()
async
{
final
String
localUsername
=
SharedPreferencesHelper
()
.
getName
();
try
{
final
String
?
name
=
await
getCesiumPlusUser
(
pubKey
);
logger
(
'currentText:
$currentText
, localUsername:
$localUsername
, _previousValue:
$_previousValue
, retrieved_name:
$name
'
);
if
(
name
!=
null
)
{
_editingController
.
text
=
name
;
currentText
=
name
;
SharedPreferencesHelper
()
.
setName
(
name:
name
);
}
else
{
_editingController
.
text
=
''
;
currentText
=
defValue
;
SharedPreferencesHelper
()
.
setName
(
name:
''
);
}
}
catch
(
e
)
{
logger
(
e
);
_editingController
.
text
=
localUsername
;
currentText
=
localUsername
;
}
_previousValue
=
_editingController
.
text
;
logger
(
'currentText:
$currentText
, localUsername:
$localUsername
, _previousValue:
$_previousValue
'
);
}
@override
void
dispose
()
{
...
...
@@ -40,13 +67,14 @@ class _CardNameEditableState extends State<CardNameEditable> {
@override
Widget
build
(
BuildContext
context
)
{
final
bool
isSet
ted
=
currentText
.
isNotEmpty
&&
currentText
!=
defValue
;
final
bool
isSet
=
currentText
.
isNotEmpty
&&
currentText
!=
defValue
;
return
_isEditingText
?
SizedBox
(
width:
150.0
,
child:
SizedBox
(
height:
40.0
,
child:
TextField
(
// focusNode: myFocusNode,
decoration:
InputDecoration
(
contentPadding:
const
EdgeInsets
.
symmetric
(
vertical:
5.0
,
horizontal:
7.0
),
...
...
@@ -58,17 +86,42 @@ class _CardNameEditableState extends State<CardNameEditable> {
focusedBorder:
const
OutlineInputBorder
(
borderSide:
BorderSide
(
width:
2.0
),
),
suffixIcon:
IconButton
(
icon:
const
Icon
(
Icons
.
check
),
onPressed:
()
{
updateName
(
_editingController
.
text
);
},
suffixIcon:
Row
(
mainAxisSize:
MainAxisSize
.
min
,
children:
<
Widget
>[
GestureDetector
(
onTap:
()
{
setState
(()
{
_isEditingText
=
false
;
});
},
child:
const
Padding
(
padding:
EdgeInsets
.
only
(
right:
8.0
),
child:
Icon
(
Icons
.
cancel_outlined
),
),
),
GestureDetector
(
onTap:
()
{
_updateValue
(
_editingController
.
text
);
},
child:
const
Padding
(
padding:
EdgeInsets
.
only
(
right:
8.0
),
child:
Icon
(
Icons
.
check
),
),
),
],
),
),
cursorColor:
Colors
.
black
,
onSubmitted:
(
String
newValue
)
{
updateName
(
newValue
);
onSubmitted:
_updateValue
,
onChanged:
(
String
value
)
{
if
(
value
.
isEmpty
)
{
_deleteValue
();
}
},
/*onSubmitted: (String newValue) {
updateName(newValue);
}, */
// maxLength: 15,
autofocus:
true
,
controller:
_editingController
,
...
...
@@ -88,17 +141,17 @@ class _CardNameEditableState extends State<CardNameEditable> {
text:
currentText
.
toUpperCase
(),
style:
const
TextStyle
(
fontFamily:
'SourceCodePro'
,
color:
Colors
.
grey
)),
if
(
isSet
ted
)
if
(
isSet
)
TextSpan
(
text:
currentText
,
style:
cardTextStyle
(
context
,
15
)),
/* TextSpan(
text: ' Lorem ipsum dolor sit amet, consectetur adipiscing elit',
style: cardTextStyle(context, 15),
), */
if
(
isSet
ted
)
if
(
isSet
)
TextSpan
(
text:
userNameSuffix
,
style:
cardTextStyle
(
context
,
1
0
),
style:
cardTextStyle
(
context
,
1
2
),
),
],
),
...
...
@@ -106,8 +159,8 @@ class _CardNameEditableState extends State<CardNameEditable> {
onTap:
()
{
setState
(()
{
try
{
_editingController
.
selection
=
TextSelection
(
baseOffset:
0
,
extentOffset:
currentText
.
length
);
/*
_editingController.selection = TextSelection(
baseOffset: 0, extentOffset: currentText.length);
*/
}
catch
(
e
)
{
logger
(
e
);
}
...
...
@@ -117,6 +170,7 @@ class _CardNameEditableState extends State<CardNameEditable> {
));
}
/*
void updateName(String newValue) {
setState(() {
if (newValue.isEmpty) {
...
...
@@ -137,5 +191,60 @@ class _CardNameEditableState extends State<CardNameEditable> {
}
_isEditingText = false;
});
}*/
Future
<
void
>
_updateValue
(
String
newValue
)
async
{
logger
(
'updating with newValue:
$newValue
'
);
try
{
if
(
_validate
(
newValue
))
{
await
createOrUpdateCesiumPlusUser
(
newValue
);
setState
(()
{
_previousValue
=
newValue
;
});
}
else
{
setState
(()
{
_editingController
.
text
=
_previousValue
;
currentText
=
_previousValue
.
isEmpty
?
defValue
:
_previousValue
;
});
}
}
catch
(
e
)
{
setState
(()
{
_editingController
.
text
=
_previousValue
;
currentText
=
_previousValue
.
isEmpty
?
defValue
:
_previousValue
;
});
}
setState
(()
{
_isEditingText
=
false
;
});
logger
(
'currentText:
$currentText
, newValue:
$newValue
, _previousValue:
$_previousValue
'
);
}
Future
<
void
>
_deleteValue
()
async
{
try
{
await
deleteCesiumPlusUser
();
SharedPreferencesHelper
()
.
setName
(
name:
''
);
setState
(()
{
_editingController
.
text
=
''
;
currentText
=
defValue
;
});
}
catch
(
e
)
{
setState
(()
{
_editingController
.
text
=
_previousValue
;
currentText
=
_previousValue
.
isEmpty
?
defValue
:
_previousValue
;
});
}
setState
(()
{
_isEditingText
=
false
;
});
logger
(
'delete with currentText:
$currentText
, _previousValue:
$_previousValue
'
);
}
bool
_validate
(
String
newValue
)
{
if
(
newValue
.
isEmpty
)
{
return
false
;
}
return
true
;
}
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment