Skip to content

Commit 3bd8e00

Browse files
authored
Merge pull request #143 from MostroP2P/feat/nostr-deep-link-support
feat: implement nostr: scheme deep link support for order discovery
2 parents 0cd718a + 40815de commit 3bd8e00

File tree

92 files changed

+1650
-662
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

92 files changed

+1650
-662
lines changed

android/app/src/main/AndroidManifest.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
android:allowBackup="false"
88
android:fullBackupContent="false"
99
android:enableOnBackInvokedCallback="true">
10+
11+
<meta-data android:name="flutter_deeplinking_enabled" android:value="false" />
1012

1113
<activity
1214
android:name=".MainActivity"
@@ -24,6 +26,14 @@
2426
<action android:name="android.intent.action.MAIN" />
2527
<category android:name="android.intent.category.LAUNCHER" />
2628
</intent-filter>
29+
30+
<!-- Deep Link Support for nostr: scheme -->
31+
<intent-filter android:autoVerify="true">
32+
<action android:name="android.intent.action.VIEW" />
33+
<category android:name="android.intent.category.DEFAULT" />
34+
<category android:name="android.intent.category.BROWSABLE" />
35+
<data android:scheme="nostr" />
36+
</intent-filter>
2737
</activity>
2838

2939
<service

integration_test/new_buy_order_test.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,6 @@ void main() {
122122
await tester.pumpAndSettle();
123123
});
124124

125-
126125
testWidgets(
127126
'User creates a new BUY order with EUR=10 and SATS=1500 using a lightning invoice',
128127
(tester) async {

integration_test/new_order_with_mocks_test.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ void main() {
77
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
88

99
group('Create Orders with mocked providers', () {
10-
testWidgets('User creates BUY order with VES=100 at premium 1', (tester) async {
10+
testWidgets('User creates BUY order with VES=100 at premium 1',
11+
(tester) async {
1112
await pumpTestApp(tester);
1213

1314
final createOrderButton = find.byKey(const Key('addOrderButton'));
@@ -44,7 +45,8 @@ void main() {
4445
expect(find.byKey(const Key('homeButton')), findsOneWidget);
4546
});
4647

47-
testWidgets('User creates SELL order with VES=100 at premium 1', (tester) async {
48+
testWidgets('User creates SELL order with VES=100 at premium 1',
49+
(tester) async {
4850
await pumpTestApp(tester);
4951

5052
final createOrderButton = find.byKey(const Key('addOrderButton'));

integration_test/test_helpers.dart

Lines changed: 108 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -37,158 +37,207 @@ class FakeSharedPreferencesAsync implements SharedPreferencesAsync {
3737
_store[key] = value;
3838
return true;
3939
}
40+
4041
@override
4142
Future<int?> getInt(String key) async => _store[key] as int?;
4243
@override
4344
Future<bool> setInt(String key, int value) async {
4445
_store[key] = value;
4546
return true;
4647
}
47-
48+
4849
@override
4950
Future<void> clear({Set<String>? allowList}) async {
5051
_store.clear();
5152
}
52-
53+
5354
@override
5455
Future<bool> containsKey(String key) async {
5556
return _store.containsKey(key);
5657
}
57-
58+
5859
@override
5960
Future<bool?> getBool(String key) async {
6061
return _store[key] as bool?;
6162
}
62-
63+
6364
@override
6465
Future<double?> getDouble(String key) async {
6566
return _store[key] as double?;
6667
}
67-
68+
6869
@override
6970
Future<Set<String>> getKeys({Set<String>? allowList}) async {
7071
return _store.keys.toSet();
7172
}
72-
73+
7374
@override
7475
Future<List<String>?> getStringList(String key) async {
7576
return _store[key] as List<String>?;
7677
}
77-
78+
7879
@override
7980
Future<bool> remove(String key) async {
8081
_store.remove(key);
8182
return true;
8283
}
83-
84+
8485
@override
8586
Future<bool> setBool(String key, bool value) async {
8687
_store[key] = value;
8788
return true;
8889
}
89-
90+
9091
@override
9192
Future<bool> setDouble(String key, double value) async {
9293
_store[key] = value;
9394
return true;
9495
}
95-
96+
9697
@override
9798
Future<bool> setStringList(String key, List<String> value) async {
9899
_store[key] = value;
99100
return true;
100101
}
101-
102+
102103
@override
103104
Future<Map<String, Object?>> getAll({Set<String>? allowList}) async {
104-
return Map.fromEntries(_store.entries.where((e) => e.value != null).map((e) => MapEntry(e.key, e.value!)));
105+
return Map.fromEntries(_store.entries
106+
.where((e) => e.value != null)
107+
.map((e) => MapEntry(e.key, e.value!)));
105108
}
106109
}
107110

108111
class FakeSecureStorage implements FlutterSecureStorage {
109112
final Map<String, String?> _store = {};
110113
@override
111-
Future<void> deleteAll({AppleOptions? iOptions, AndroidOptions? aOptions, LinuxOptions? lOptions, AppleOptions? mOptions, WindowsOptions? wOptions, WebOptions? webOptions}) async {
114+
Future<void> deleteAll(
115+
{AppleOptions? iOptions,
116+
AndroidOptions? aOptions,
117+
LinuxOptions? lOptions,
118+
AppleOptions? mOptions,
119+
WindowsOptions? wOptions,
120+
WebOptions? webOptions}) async {
112121
_store.clear();
113122
}
114123

115124
@override
116-
Future<String?> read({required String key, AppleOptions? iOptions, AndroidOptions? aOptions, LinuxOptions? lOptions, AppleOptions? mOptions, WindowsOptions? wOptions, WebOptions? webOptions}) async {
125+
Future<String?> read(
126+
{required String key,
127+
AppleOptions? iOptions,
128+
AndroidOptions? aOptions,
129+
LinuxOptions? lOptions,
130+
AppleOptions? mOptions,
131+
WindowsOptions? wOptions,
132+
WebOptions? webOptions}) async {
117133
return _store[key];
118134
}
119135

120136
@override
121-
Future<void> write({required String key, required String? value, AppleOptions? iOptions, AndroidOptions? aOptions, LinuxOptions? lOptions, AppleOptions? mOptions, WindowsOptions? wOptions, WebOptions? webOptions}) async {
137+
Future<void> write(
138+
{required String key,
139+
required String? value,
140+
AppleOptions? iOptions,
141+
AndroidOptions? aOptions,
142+
LinuxOptions? lOptions,
143+
AppleOptions? mOptions,
144+
WindowsOptions? wOptions,
145+
WebOptions? webOptions}) async {
122146
_store[key] = value;
123147
}
124148

125149
// Unused methods
126150
@override
127-
Future<void> delete({required String key, AppleOptions? iOptions, AndroidOptions? aOptions, LinuxOptions? lOptions, AppleOptions? mOptions, WindowsOptions? wOptions, WebOptions? webOptions}) async {
151+
Future<void> delete(
152+
{required String key,
153+
AppleOptions? iOptions,
154+
AndroidOptions? aOptions,
155+
LinuxOptions? lOptions,
156+
AppleOptions? mOptions,
157+
WindowsOptions? wOptions,
158+
WebOptions? webOptions}) async {
128159
_store.remove(key);
129160
}
130161

131162
@override
132-
Future<Map<String, String>> readAll({AppleOptions? iOptions, AndroidOptions? aOptions, LinuxOptions? lOptions, AppleOptions? mOptions, WindowsOptions? wOptions, WebOptions? webOptions}) async {
133-
return Map.fromEntries(_store.entries.where((e) => e.value != null).map((e) => MapEntry(e.key, e.value!)));
163+
Future<Map<String, String>> readAll(
164+
{AppleOptions? iOptions,
165+
AndroidOptions? aOptions,
166+
LinuxOptions? lOptions,
167+
AppleOptions? mOptions,
168+
WindowsOptions? wOptions,
169+
WebOptions? webOptions}) async {
170+
return Map.fromEntries(_store.entries
171+
.where((e) => e.value != null)
172+
.map((e) => MapEntry(e.key, e.value!)));
134173
}
135174

136175
@override
137176
// TODO: implement aOptions
138177
AndroidOptions get aOptions => throw UnimplementedError();
139-
178+
140179
@override
141-
Future<bool> containsKey({required String key, AppleOptions? iOptions, AndroidOptions? aOptions, LinuxOptions? lOptions, WebOptions? webOptions, AppleOptions? mOptions, WindowsOptions? wOptions}) {
180+
Future<bool> containsKey(
181+
{required String key,
182+
AppleOptions? iOptions,
183+
AndroidOptions? aOptions,
184+
LinuxOptions? lOptions,
185+
WebOptions? webOptions,
186+
AppleOptions? mOptions,
187+
WindowsOptions? wOptions}) {
142188
// TODO: implement containsKey
143189
throw UnimplementedError();
144190
}
145-
191+
146192
@override
147193
// TODO: implement iOptions
148194
IOSOptions get iOptions => throw UnimplementedError();
149-
195+
150196
@override
151197
Future<bool?> isCupertinoProtectedDataAvailable() {
152198
// TODO: implement isCupertinoProtectedDataAvailable
153199
throw UnimplementedError();
154200
}
155-
201+
156202
@override
157203
// TODO: implement lOptions
158204
LinuxOptions get lOptions => throw UnimplementedError();
159-
205+
160206
@override
161207
// TODO: implement mOptions
162208
AppleOptions get mOptions => throw UnimplementedError();
163-
209+
164210
@override
165211
// TODO: implement onCupertinoProtectedDataAvailabilityChanged
166-
Stream<bool>? get onCupertinoProtectedDataAvailabilityChanged => throw UnimplementedError();
167-
212+
Stream<bool>? get onCupertinoProtectedDataAvailabilityChanged =>
213+
throw UnimplementedError();
214+
168215
@override
169-
void registerListener({required String key, required ValueChanged<String?> listener}) {
216+
void registerListener(
217+
{required String key, required ValueChanged<String?> listener}) {
170218
// TODO: implement registerListener
171219
}
172-
220+
173221
@override
174222
void unregisterAllListeners() {
175223
// TODO: implement unregisterAllListeners
176224
}
177-
225+
178226
@override
179227
void unregisterAllListenersForKey({required String key}) {
180228
// TODO: implement unregisterAllListenersForKey
181229
}
182-
230+
183231
@override
184-
void unregisterListener({required String key, required ValueChanged<String?> listener}) {
232+
void unregisterListener(
233+
{required String key, required ValueChanged<String?> listener}) {
185234
// TODO: implement unregisterListener
186235
}
187-
236+
188237
@override
189238
// TODO: implement wOptions
190239
WindowsOptions get wOptions => throw UnimplementedError();
191-
240+
192241
@override
193242
// TODO: implement webOptions
194243
WebOptions get webOptions => throw UnimplementedError();
@@ -243,7 +292,8 @@ class FakeMostroService implements MostroService {
243292
Future<void> takeBuyOrder(String orderId, int? amount) async {}
244293

245294
@override
246-
Future<void> takeSellOrder(String orderId, int? amount, String? lnAddress) async {}
295+
Future<void> takeSellOrder(
296+
String orderId, int? amount, String? lnAddress) async {}
247297

248298
@override
249299
Future<void> sendInvoice(String orderId, String invoice, int? amount) async {}
@@ -264,7 +314,8 @@ class FakeMostroService implements MostroService {
264314
Future<void> submitRating(String orderId, int rating) async {}
265315

266316
@override
267-
Future<Session> publishOrder(MostroMessage order) => throw UnimplementedError();
317+
Future<Session> publishOrder(MostroMessage order) =>
318+
throw UnimplementedError();
268319

269320
@override
270321
void updateSettings(Settings settings) {}
@@ -284,27 +335,27 @@ Future<void> pumpTestApp(WidgetTester tester) async {
284335
overrides: [
285336
settingsProvider.overrideWith((ref) => settingsNotifier),
286337
currencyCodesProvider.overrideWith((ref) async => {
287-
'VES': Currency(
288-
symbol: 'Bs',
289-
name: 'Venezuelan Bolívar',
290-
symbolNative: 'Bs',
291-
code: 'VES',
292-
emoji: '🇻🇪',
293-
decimalDigits: 2,
294-
namePlural: 'Venezuelan bolívars',
295-
price: false,
296-
),
297-
'USD': Currency(
298-
symbol: '\$',
299-
name: 'US Dollar',
300-
symbolNative: '\$',
301-
code: 'USD',
302-
emoji: '🇺🇸',
303-
decimalDigits: 2,
304-
namePlural: 'US dollars',
305-
price: false,
306-
),
307-
}),
338+
'VES': Currency(
339+
symbol: 'Bs',
340+
name: 'Venezuelan Bolívar',
341+
symbolNative: 'Bs',
342+
code: 'VES',
343+
emoji: '🇻🇪',
344+
decimalDigits: 2,
345+
namePlural: 'Venezuelan bolívars',
346+
price: false,
347+
),
348+
'USD': Currency(
349+
symbol: '\$',
350+
name: 'US Dollar',
351+
symbolNative: '\$',
352+
code: 'USD',
353+
emoji: '🇺🇸',
354+
decimalDigits: 2,
355+
namePlural: 'US dollars',
356+
price: false,
357+
),
358+
}),
308359
sharedPreferencesProvider.overrideWithValue(prefs),
309360
secureStorageProvider.overrideWithValue(secure),
310361
mostroDatabaseProvider.overrideWithValue(db),

ios/Runner/Info.plist

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@
4343
</array>
4444
<key>CADisableMinimumFrameDurationOnPhone</key>
4545
<true />
46+
<key>FlutterDeepLinkingEnabled</key>
47+
<false />
4648
<key>UIApplicationSupportsIndirectInputEvents</key>
4749
<true />
4850
<key>NSCameraUsageDescription</key>
@@ -53,5 +55,19 @@
5355
<string>processing</string>
5456
<string>remote-notification</string>
5557
</array>
58+
<!-- Deep Link Support for nostr: scheme -->
59+
<key>CFBundleURLTypes</key>
60+
<array>
61+
<dict>
62+
<key>CFBundleURLName</key>
63+
<string>nostr.scheme</string>
64+
<key>CFBundleURLSchemes</key>
65+
<array>
66+
<string>nostr</string>
67+
</array>
68+
<key>CFBundleTypeRole</key>
69+
<string>Editor</string>
70+
</dict>
71+
</array>
5672
</dict>
5773
</plist>

0 commit comments

Comments
 (0)