Skip to content

Commit 3a7b130

Browse files
Merge pull request #297 from sagar-deriv/feat/subscribtion_exchange_rates
feat: add subscription methods for `exchange rates`
2 parents f86ec5c + 8b6d143 commit 3a7b130

File tree

4 files changed

+157
-1
lines changed

4 files changed

+157
-1
lines changed

example/lib/pages/main_page.dart

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import 'package:flutter_deriv_api_example/blocs/active_symbols/active_symbols_bl
44
import 'package:flutter_deriv_api_example/blocs/available_contracts/available_contracts_bloc.dart';
55
import 'package:flutter_deriv_api_example/widgets/active_symbols_widget.dart';
66
import 'package:flutter_deriv_api_example/widgets/contracts_type_widget.dart';
7+
import 'package:flutter_deriv_api_example/widgets/exchange_rate_widget.dart';
78
import 'package:flutter_deriv_api_example/widgets/price_proposal_widget.dart';
89

910
/// MainPage
@@ -47,6 +48,7 @@ class _MainPageState extends State<MainPage> {
4748
Expanded(child: ActiveSymbolsWidget()),
4849
Expanded(child: ContractsTypeWidget()),
4950
Expanded(flex: 2, child: PriceProposalWidget()),
51+
const Expanded(flex: 2, child: ExchangeRateWidget()),
5052
],
5153
),
5254
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import 'dart:async';
2+
import 'dart:developer';
3+
4+
import 'package:flutter/material.dart';
5+
import 'package:flutter_deriv_api/api/response/exchange_rates_response_result.dart';
6+
import 'package:flutter_deriv_api/api/response/exchange_rates_response_extended.dart';
7+
import 'package:flutter_deriv_api/basic_api/generated/exchange_rates_send.dart';
8+
9+
/// Test widget for the exchange rates for BTC -> USD.
10+
class ExchangeRateWidget extends StatefulWidget {
11+
/// Test widget for exchange rates for BTC -> USD
12+
const ExchangeRateWidget({super.key});
13+
14+
@override
15+
State<ExchangeRateWidget> createState() => _ExchangeRateWidgetState();
16+
}
17+
18+
class _ExchangeRateWidgetState extends State<ExchangeRateWidget> {
19+
double value = 0;
20+
21+
bool isSubscribed = false;
22+
int exchangeUpdateTime = 0;
23+
String subscriptionId = '';
24+
25+
Timer? _refreshingTimer;
26+
27+
@override
28+
Widget build(BuildContext context) => Column(
29+
mainAxisSize: MainAxisSize.min,
30+
children: [
31+
ElevatedButton(
32+
onPressed: () =>
33+
isSubscribed ? _unsubscribe() : _subscribeUSDtoBTC(),
34+
child: isSubscribed
35+
? const Text('Unsubscribe')
36+
: const Text('Subscribe to exchange rate'),
37+
),
38+
const Text('USD:'),
39+
Text(value.toString()),
40+
const SizedBox(height: 12),
41+
const SizedBox(height: 12),
42+
Text(
43+
'Last updated after: ${exchangeUpdateTime.toStringAsFixed(2)} seconds',
44+
)
45+
],
46+
);
47+
48+
Future<void> _subscribeUSDtoBTC() async {
49+
final Stream<ExchangeRatesResponse?> ratesStream =
50+
ExchangeRatesResponseExtended.subscribeToExchangeRates(
51+
const ExchangeRatesRequest(
52+
baseCurrency: 'BTC',
53+
targetCurrency: 'USD',
54+
subscribe: true,
55+
));
56+
57+
// ignore: cascade_invocations
58+
ratesStream.listen((ExchangeRatesResponse? response) {
59+
setState(() {
60+
subscriptionId = response!.subscription!.id;
61+
isSubscribed = true;
62+
value = response.exchangeRates!.rates!['USD'] as double;
63+
_resetTimer();
64+
});
65+
});
66+
}
67+
68+
void _resetTimer() {
69+
_refreshingTimer?.cancel();
70+
71+
_refreshingTimer = Timer.periodic(
72+
const Duration(seconds: 1),
73+
(Timer timer) {
74+
exchangeUpdateTime = timer.tick;
75+
},
76+
);
77+
}
78+
79+
Future<void> _unsubscribe() async {
80+
try {
81+
final bool $ =
82+
await ExchangeRatesResponseExtended.unsubscribeFromExchangeRates(
83+
subscriptionId);
84+
$.toString();
85+
_refreshingTimer?.cancel();
86+
} on Exception catch (e) {
87+
log(e.toString());
88+
}
89+
setState(() {
90+
isSubscribed = false;
91+
});
92+
}
93+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import 'package:deriv_dependency_injector/dependency_injector.dart';
2+
import 'package:flutter_deriv_api/api/exceptions/base_api_exception.dart';
3+
import 'package:flutter_deriv_api/api/models/base_exception_model.dart';
4+
import 'package:flutter_deriv_api/api/response/exchange_rates_response_result.dart';
5+
import 'package:flutter_deriv_api/basic_api/generated/api.dart';
6+
import 'package:flutter_deriv_api/basic_api/response.dart';
7+
import 'package:flutter_deriv_api/helpers/helpers.dart';
8+
import 'package:flutter_deriv_api/services/connection/api_manager/base_api.dart';
9+
import 'package:flutter_deriv_api/services/connection/call_manager/base_call_manager.dart';
10+
11+
/// Extended functionality for [ExchangeRatesResponse] class.
12+
class ExchangeRatesResponseExtended extends ExchangeRatesResponse {
13+
static final BaseAPI _api = Injector()<BaseAPI>();
14+
15+
/// This will subscribe to currency exchange.<br>
16+
/// Inside [ExchangeRateRequest] class:
17+
/// [baseCurrency]: currency that should be exchanged like USD, BTC or any other.
18+
/// [targetCurrency]: currency that you want to exchange to.
19+
/// Incase of error, It will throw [BaseAPIException].
20+
static Stream<ExchangeRatesResponse?> subscribeToExchangeRates(
21+
ExchangeRatesRequest request, {
22+
RequestCompareFunction? comparePredicate,
23+
}) =>
24+
_api
25+
.subscribe(request: request, comparePredicate: comparePredicate)!
26+
.map<ExchangeRatesResponse?>(
27+
(Response response) {
28+
checkException(
29+
response: response,
30+
exceptionCreator: ({BaseExceptionModel? baseExceptionModel}) =>
31+
BaseAPIException(baseExceptionModel: baseExceptionModel),
32+
);
33+
34+
if (response is ExchangeRatesReceive) {
35+
return ExchangeRatesResponse.fromJson(
36+
response.exchangeRates, response.subscription);
37+
} else {
38+
throw Exception('Bad response received');
39+
}
40+
},
41+
);
42+
43+
/// unsubscribe from the subscribed exchange rates <br>
44+
/// In case of error, It will throw [BaseAPIException].
45+
static Future<bool> unsubscribeFromExchangeRates(
46+
String subscriptionId) async {
47+
final ForgetReceive response =
48+
await _api.unsubscribe(subscriptionId: subscriptionId);
49+
checkException(
50+
response: response,
51+
exceptionCreator: ({BaseExceptionModel? baseExceptionModel}) =>
52+
BaseAPIException(baseExceptionModel: baseExceptionModel),
53+
);
54+
return response.forget!;
55+
}
56+
}

lib/api/response/exchange_rates_response_result.dart

+6-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import 'package:flutter_deriv_api/basic_api/generated/exchange_rates_send.dart';
99
import 'package:flutter_deriv_api/helpers/helpers.dart';
1010
import 'package:flutter_deriv_api/services/connection/api_manager/base_api.dart';
1111
import 'package:deriv_dependency_injector/dependency_injector.dart';
12+
import 'package:flutter_deriv_api/api/response/exchange_rates_response_extended.dart';
1213

1314
/// Exchange rates response model class.
1415
abstract class ExchangeRatesResponseModel {
@@ -25,7 +26,10 @@ abstract class ExchangeRatesResponseModel {
2526
final Subscription? subscription;
2627
}
2728

28-
/// Exchange rates response class.
29+
/// Exchange rates response class. <br>
30+
///
31+
/// DeveloperNote: In case of adding new functionality to this class, please use the extended version of the class i.e [ExchangeRatesResponseExtended]
32+
2933
class ExchangeRatesResponse extends ExchangeRatesResponseModel {
3034
/// Initializes Exchange rates response class.
3135
const ExchangeRatesResponse({
@@ -88,6 +92,7 @@ class ExchangeRatesResponse extends ExchangeRatesResponseModel {
8892
///
8993
/// For parameters information refer to [ExchangeRatesRequest].
9094
/// Throws an [BaseAPIException] if API response contains an error.
95+
/// Developer NOTE: to use the realtime update to exchange rates please refer to [ExchangeRatesResponseExtended.subscribeToExchangeRates] method.
9196
static Future<ExchangeRates> fetchExchangeRates(
9297
ExchangeRatesRequest request,
9398
) async {

0 commit comments

Comments
 (0)