Add user image to Nostr

Add fetching address from text for tokens
This commit is contained in:
OmarHatem 2024-03-02 02:13:03 +02:00
parent ef43032460
commit a86c1dfc5d
7 changed files with 68 additions and 28 deletions

View file

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

View file

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

View file

@ -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,
@ -111,8 +114,8 @@ class AddressResolver {
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(
@ -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);
} }
} }
} }

View file

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

View file

@ -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) {

View file

@ -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';

View file

@ -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,6 +43,7 @@ class TwitterApi {
} }
static Tweet? _getPinnedTweet(Map<String, dynamic> responseJSON) { static Tweet? _getPinnedTweet(Map<String, dynamic> responseJSON) {
try {
final tweetId = responseJSON['data']['pinned_tweet_id'] as String?; final tweetId = responseJSON['data']['pinned_tweet_id'] as String?;
if (tweetId == null || responseJSON['includes'] == null) return null; if (tweetId == null || responseJSON['includes'] == null) return null;
@ -55,5 +59,8 @@ class TwitterApi {
(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;
}
} }
} }