mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-22 19:49:22 +00:00
Add user image to Nostr
Add fetching address from text for tokens
This commit is contained in:
parent
ef43032460
commit
a86c1dfc5d
7 changed files with 68 additions and 28 deletions
|
@ -247,7 +247,16 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
|
||||||
return CryptoCurrency._rawCurrencyMap[raw]!;
|
return CryptoCurrency._rawCurrencyMap[raw]!;
|
||||||
}
|
}
|
||||||
|
|
||||||
static CryptoCurrency fromString(String name) {
|
// TODO: refactor this
|
||||||
|
static CryptoCurrency fromString(String name, {CryptoCurrency? walletCurrency}) {
|
||||||
|
try {
|
||||||
|
return CryptoCurrency.all.firstWhere((element) =>
|
||||||
|
element.title.toLowerCase() == name &&
|
||||||
|
(element.tag == null ||
|
||||||
|
element.tag == walletCurrency?.title ||
|
||||||
|
element.tag == walletCurrency?.tag));
|
||||||
|
} catch (_) {}
|
||||||
|
|
||||||
if (CryptoCurrency._nameCurrencyMap[name.toLowerCase()] == null) {
|
if (CryptoCurrency._nameCurrencyMap[name.toLowerCase()] == null) {
|
||||||
final s = 'Unexpected token: $name for CryptoCurrency fromString';
|
final s = 'Unexpected token: $name for CryptoCurrency fromString';
|
||||||
throw ArgumentError.value(name, 'name', s);
|
throw ArgumentError.value(name, 'name', s);
|
||||||
|
|
|
@ -295,6 +295,16 @@ class AddressValidator extends TextValidator {
|
||||||
case CryptoCurrency.sol:
|
case CryptoCurrency.sol:
|
||||||
return '([^0-9a-zA-Z]|^)[1-9A-HJ-NP-Za-km-z]{43,44}([^0-9a-zA-Z]|\$)';
|
return '([^0-9a-zA-Z]|^)[1-9A-HJ-NP-Za-km-z]{43,44}([^0-9a-zA-Z]|\$)';
|
||||||
default:
|
default:
|
||||||
|
if (type.tag == CryptoCurrency.eth.title) {
|
||||||
|
return '0x[0-9a-zA-Z]{42}';
|
||||||
|
}
|
||||||
|
if (type.tag == CryptoCurrency.maticpoly.tag) {
|
||||||
|
return '0x[0-9a-zA-Z]{42}';
|
||||||
|
}
|
||||||
|
if (type.tag == CryptoCurrency.sol.title) {
|
||||||
|
return '([^0-9a-zA-Z]|^)[1-9A-HJ-NP-Za-km-z]{43,44}([^0-9a-zA-Z]|\$)';
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,8 @@ class AddressResolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
final match = RegExp(addressPattern).firstMatch(raw);
|
final match = RegExp(addressPattern).firstMatch(raw);
|
||||||
return match?.group(0)?.replaceAllMapped(RegExp('[^0-9a-zA-Z]|bitcoincash:|nano_'), (Match match) {
|
return match?.group(0)?.replaceAllMapped(RegExp('[^0-9a-zA-Z]|bitcoincash:|nano_'),
|
||||||
|
(Match match) {
|
||||||
String group = match.group(0)!;
|
String group = match.group(0)!;
|
||||||
if (group.startsWith('bitcoincash:') || group.startsWith('nano_')) {
|
if (group.startsWith('bitcoincash:') || group.startsWith('nano_')) {
|
||||||
return group;
|
return group;
|
||||||
|
@ -68,7 +69,7 @@ class AddressResolver {
|
||||||
return emailRegex.hasMatch(address);
|
return emailRegex.hasMatch(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: refactor this to take Crypto currency instead of ticker, or at least pass in the tag as well
|
||||||
Future<ParsedAddress> resolve(BuildContext context, String text, String ticker) async {
|
Future<ParsedAddress> resolve(BuildContext context, String text, String ticker) async {
|
||||||
try {
|
try {
|
||||||
if (text.startsWith('@') && !text.substring(1).contains('@')) {
|
if (text.startsWith('@') && !text.substring(1).contains('@')) {
|
||||||
|
@ -76,7 +77,8 @@ class AddressResolver {
|
||||||
final formattedName = text.substring(1);
|
final formattedName = text.substring(1);
|
||||||
final twitterUser = await TwitterApi.lookupUserByName(userName: formattedName);
|
final twitterUser = await TwitterApi.lookupUserByName(userName: formattedName);
|
||||||
final addressFromBio = extractAddressByType(
|
final addressFromBio = extractAddressByType(
|
||||||
raw: twitterUser.description, type: CryptoCurrency.fromString(ticker));
|
raw: twitterUser.description,
|
||||||
|
type: CryptoCurrency.fromString(ticker, walletCurrency: wallet.currency));
|
||||||
if (addressFromBio != null) {
|
if (addressFromBio != null) {
|
||||||
return ParsedAddress.fetchTwitterAddress(
|
return ParsedAddress.fetchTwitterAddress(
|
||||||
address: addressFromBio,
|
address: addressFromBio,
|
||||||
|
@ -87,8 +89,9 @@ class AddressResolver {
|
||||||
|
|
||||||
final pinnedTweet = twitterUser.pinnedTweet?.text;
|
final pinnedTweet = twitterUser.pinnedTweet?.text;
|
||||||
if (pinnedTweet != null) {
|
if (pinnedTweet != null) {
|
||||||
final addressFromPinnedTweet =
|
final addressFromPinnedTweet = extractAddressByType(
|
||||||
extractAddressByType(raw: pinnedTweet, type: CryptoCurrency.fromString(ticker));
|
raw: pinnedTweet,
|
||||||
|
type: CryptoCurrency.fromString(ticker, walletCurrency: wallet.currency));
|
||||||
if (addressFromPinnedTweet != null) {
|
if (addressFromPinnedTweet != null) {
|
||||||
return ParsedAddress.fetchTwitterAddress(
|
return ParsedAddress.fetchTwitterAddress(
|
||||||
address: addressFromPinnedTweet,
|
address: addressFromPinnedTweet,
|
||||||
|
@ -108,11 +111,11 @@ class AddressResolver {
|
||||||
final userName = subText.substring(0, hostNameIndex);
|
final userName = subText.substring(0, hostNameIndex);
|
||||||
|
|
||||||
final mastodonUser =
|
final mastodonUser =
|
||||||
await MastodonAPI.lookupUserByUserName(userName: userName, apiHost: hostName);
|
await MastodonAPI.lookupUserByUserName(userName: userName, apiHost: hostName);
|
||||||
|
|
||||||
if (mastodonUser != null) {
|
if (mastodonUser != null) {
|
||||||
String? addressFromBio =
|
String? addressFromBio = extractAddressByType(
|
||||||
extractAddressByType(raw: mastodonUser.note, type: CryptoCurrency.fromString(ticker));
|
raw: mastodonUser.note, type: CryptoCurrency.fromString(ticker));
|
||||||
|
|
||||||
if (addressFromBio != null) {
|
if (addressFromBio != null) {
|
||||||
return ParsedAddress.fetchMastodonAddress(
|
return ParsedAddress.fetchMastodonAddress(
|
||||||
|
@ -122,7 +125,7 @@ class AddressResolver {
|
||||||
profileName: mastodonUser.username);
|
profileName: mastodonUser.username);
|
||||||
} else {
|
} else {
|
||||||
final pinnedPosts =
|
final pinnedPosts =
|
||||||
await MastodonAPI.getPinnedPosts(userId: mastodonUser.id, apiHost: hostName);
|
await MastodonAPI.getPinnedPosts(userId: mastodonUser.id, apiHost: hostName);
|
||||||
|
|
||||||
if (pinnedPosts.isNotEmpty) {
|
if (pinnedPosts.isNotEmpty) {
|
||||||
final userPinnedPostsText = pinnedPosts.map((item) => item.content).join('\n');
|
final userPinnedPostsText = pinnedPosts.map((item) => item.content).join('\n');
|
||||||
|
@ -150,7 +153,7 @@ class AddressResolver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (text.hasOnlyEmojis) {
|
if (text.hasOnlyEmojis) {
|
||||||
if(settingsStore.lookupsYatService) {
|
if (settingsStore.lookupsYatService) {
|
||||||
if (walletType != WalletType.haven) {
|
if (walletType != WalletType.haven) {
|
||||||
final addresses = await yatService.fetchYatAddress(text, ticker);
|
final addresses = await yatService.fetchYatAddress(text, ticker);
|
||||||
return ParsedAddress.fetchEmojiAddress(addresses: addresses, name: text);
|
return ParsedAddress.fetchEmojiAddress(addresses: addresses, name: text);
|
||||||
|
@ -166,7 +169,7 @@ class AddressResolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unstoppableDomains.any((domain) => name.trim() == domain)) {
|
if (unstoppableDomains.any((domain) => name.trim() == domain)) {
|
||||||
if(settingsStore.lookupsUnstoppableDomains) {
|
if (settingsStore.lookupsUnstoppableDomains) {
|
||||||
final address = await fetchUnstoppableDomainAddress(text, ticker);
|
final address = await fetchUnstoppableDomainAddress(text, ticker);
|
||||||
return ParsedAddress.fetchUnstoppableDomainAddress(address: address, name: text);
|
return ParsedAddress.fetchUnstoppableDomainAddress(address: address, name: text);
|
||||||
}
|
}
|
||||||
|
@ -182,7 +185,7 @@ class AddressResolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (formattedName.contains(".")) {
|
if (formattedName.contains(".")) {
|
||||||
if(settingsStore.lookupsOpenAlias) {
|
if (settingsStore.lookupsOpenAlias) {
|
||||||
final txtRecord = await OpenaliasRecord.lookupOpenAliasRecord(formattedName);
|
final txtRecord = await OpenaliasRecord.lookupOpenAliasRecord(formattedName);
|
||||||
if (txtRecord != null) {
|
if (txtRecord != null) {
|
||||||
final record = await OpenaliasRecord.fetchAddressAndName(
|
final record = await OpenaliasRecord.fetchAddressAndName(
|
||||||
|
@ -201,7 +204,11 @@ class AddressResolver {
|
||||||
String? addressFromBio = extractAddressByType(
|
String? addressFromBio = extractAddressByType(
|
||||||
raw: nostrUserData.about, type: CryptoCurrency.fromString(ticker));
|
raw: nostrUserData.about, type: CryptoCurrency.fromString(ticker));
|
||||||
if (addressFromBio != null) {
|
if (addressFromBio != null) {
|
||||||
return ParsedAddress.nostrAddress(address: addressFromBio, name: text);
|
return ParsedAddress.nostrAddress(
|
||||||
|
address: addressFromBio,
|
||||||
|
name: text,
|
||||||
|
profileImageUrl: nostrUserData.picture,
|
||||||
|
profileName: nostrUserData.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,11 +119,17 @@ class ParsedAddress {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
factory ParsedAddress.nostrAddress({required String address, required String name}) {
|
factory ParsedAddress.nostrAddress(
|
||||||
|
{required String address,
|
||||||
|
required String name,
|
||||||
|
required String profileImageUrl,
|
||||||
|
required String profileName}) {
|
||||||
return ParsedAddress(
|
return ParsedAddress(
|
||||||
addresses: [address],
|
addresses: [address],
|
||||||
name: name,
|
name: name,
|
||||||
parseFrom: ParseFrom.nostr,
|
parseFrom: ParseFrom.nostr,
|
||||||
|
profileImageUrl: profileImageUrl,
|
||||||
|
profileName: profileName,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,8 @@ Future<String> extractAddressFromParsed(
|
||||||
title = S.of(context).address_detected;
|
title = S.of(context).address_detected;
|
||||||
content = S.of(context).extracted_address_content('${parsedAddress.name} (Nostr NIP-05)');
|
content = S.of(context).extracted_address_content('${parsedAddress.name} (Nostr NIP-05)');
|
||||||
address = parsedAddress.addresses.first;
|
address = parsedAddress.addresses.first;
|
||||||
|
profileImageUrl = parsedAddress.profileImageUrl;
|
||||||
|
profileName = parsedAddress.profileName;
|
||||||
break;
|
break;
|
||||||
case ParseFrom.yatRecord:
|
case ParseFrom.yatRecord:
|
||||||
if (parsedAddress.name.isEmpty) {
|
if (parsedAddress.name.isEmpty) {
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import 'package:cake_wallet/src/screens/receive/widgets/header_tile.dart';
|
|
||||||
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
import 'package:cake_wallet/src/widgets/section_divider.dart';
|
import 'package:cake_wallet/src/widgets/section_divider.dart';
|
||||||
|
|
|
@ -32,7 +32,10 @@ class TwitterApi {
|
||||||
}
|
}
|
||||||
|
|
||||||
final Map<String, dynamic> responseJSON = jsonDecode(response.body) as Map<String, dynamic>;
|
final Map<String, dynamic> responseJSON = jsonDecode(response.body) as Map<String, dynamic>;
|
||||||
if (responseJSON['errors'] != null) {
|
if (responseJSON['errors'] != null &&
|
||||||
|
!responseJSON['errors'][0]['detail']
|
||||||
|
.toString()
|
||||||
|
.contains("Could not find tweet with pinned_tweet_id")) {
|
||||||
throw Exception(responseJSON['errors'][0]['detail']);
|
throw Exception(responseJSON['errors'][0]['detail']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,20 +43,24 @@ class TwitterApi {
|
||||||
}
|
}
|
||||||
|
|
||||||
static Tweet? _getPinnedTweet(Map<String, dynamic> responseJSON) {
|
static Tweet? _getPinnedTweet(Map<String, dynamic> responseJSON) {
|
||||||
final tweetId = responseJSON['data']['pinned_tweet_id'] as String?;
|
try {
|
||||||
if (tweetId == null || responseJSON['includes'] == null) return null;
|
final tweetId = responseJSON['data']['pinned_tweet_id'] as String?;
|
||||||
|
if (tweetId == null || responseJSON['includes'] == null) return null;
|
||||||
|
|
||||||
final tweetIncludes = List.from(responseJSON['includes']['tweets'] as List);
|
final tweetIncludes = List.from(responseJSON['includes']['tweets'] as List);
|
||||||
final pinnedTweetData = tweetIncludes.firstWhere(
|
final pinnedTweetData = tweetIncludes.firstWhere(
|
||||||
(tweet) => tweet['id'] == tweetId,
|
(tweet) => tweet['id'] == tweetId,
|
||||||
orElse: () => null,
|
orElse: () => null,
|
||||||
) as Map<String, dynamic>?;
|
) as Map<String, dynamic>?;
|
||||||
|
|
||||||
if (pinnedTweetData == null) return null;
|
if (pinnedTweetData == null) return null;
|
||||||
|
|
||||||
final pinnedTweetText =
|
final pinnedTweetText =
|
||||||
(pinnedTweetData['note_tweet']?['text'] ?? pinnedTweetData['text']) as String;
|
(pinnedTweetData['note_tweet']?['text'] ?? pinnedTweetData['text']) as String;
|
||||||
|
|
||||||
return Tweet(id: tweetId, text: pinnedTweetText);
|
return Tweet(id: tweetId, text: pinnedTweetText);
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue