Skip to content

Commit

Permalink
Sound null safety
Browse files Browse the repository at this point in the history
  • Loading branch information
Sominemo committed Mar 3, 2021
1 parent 93a6594 commit 7327265
Show file tree
Hide file tree
Showing 9 changed files with 252 additions and 151 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
## 1.4.0-nullsafety.1
- Null safety
- Bugs fixed

## 1.3.0
- Breaking change: /mcc/mcc.dart removed
- Docs fixes

## 1.2.2
- Fixed CurrencyInfo integer parsing error

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Monobank API SDK for Dart

Author is not related to monobank team.
This package is unofficial

## Usage

Expand Down
58 changes: 32 additions & 26 deletions lib/src/api.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import 'dart:async';
import 'dart:convert';

import 'dart:math' as math;
import 'package:http/http.dart' as http;

/// Possible error types that happen to API
Expand Down Expand Up @@ -136,18 +135,18 @@ class APIRequest {
this.useAuth = false,

/// JSON body to send
Map<String, String> data,
Map<String, String> data = const {},

/// Headers to send
///
/// ```
/// Key: Value
/// ```
Map<String, String> headers,
Map<String, String> headers = const {},
this.httpMethod = APIHttpMethod.GET,
}) : _completer = Completer(),
data = data ?? {},
headers = headers ?? {},
data = Map.from(data),
headers = Map.from(headers),
_originalData = data,
_originalHeaders = headers;

Expand All @@ -169,7 +168,7 @@ class APIRequest {
/// ```
/// APIRequestA.methodId == APIRequestB.methodId
/// ```
final String methodId;
final String? methodId;

/// API Request Flags
///
Expand Down Expand Up @@ -240,7 +239,7 @@ class APIResponse {
/// HTTP Response headers
final Map<String, String> headers;

APIResponse._(this.body, this.statusCode, this.headers);
const APIResponse._(this.body, this.statusCode, this.headers);
}

/// Requests sender and throttling container
Expand All @@ -261,10 +260,10 @@ class API {
this.domain, {
this.globalTimeout = Duration.zero,
this.token,
Map<String, Duration> requestTimeouts,
Uri noAuthDomain,
Map<String, Duration> requestTimeouts = const {},
Uri? noAuthDomain,
}) : noAuthDomain = noAuthDomain ?? domain {
this.requestTimeouts = requestTimeouts ?? {};
this.requestTimeouts = requestTimeouts;
}

/// Root path
Expand All @@ -284,7 +283,7 @@ class API {
///
/// Is being appended in [API.authAttacher] when
/// [APIRequest.useAuth] == `true`.
final String token;
final String? token;

/// Minimal timeout between all requests
///
Expand Down Expand Up @@ -337,7 +336,7 @@ class API {
/// Returns last time request of class was sent if specified
///
/// Returns `DateTime.fromMillisecondsSinceEpoch(0)` if never was sent
DateTime lastRequest({String methodId}) => methodId == null
DateTime lastRequest({String? methodId}) => methodId == null
? _lastRequest
: (_lastRequests[methodId] ?? DateTime.fromMillisecondsSinceEpoch(0));

Expand All @@ -347,7 +346,7 @@ class API {
///
/// Must be checked again before sending the request, because it returns
/// **minimum** required time, not the actual one
Duration willFreeIn({String methodId}) {
Duration willFreeIn({String? methodId}) {
// Time since last request
final timePassed = DateTime.now().difference(_lastRequest);

Expand Down Expand Up @@ -388,7 +387,7 @@ class API {
///
/// Can be also calculated by comparasion of API.isRequestImmediate
/// to [Duration.zero]
bool isRequestImmediate(String methodId) =>
bool isRequestImmediate(String? methodId) =>
willFreeIn(methodId: methodId) == Duration.zero;

/// Evaluate the request
Expand Down Expand Up @@ -450,7 +449,7 @@ class API {

Duration globalWait;

Duration minDelay;
Duration? minDelay;

for (var request in _cart.toList()) {
try {
Expand All @@ -462,7 +461,7 @@ class API {
(request.settings & APIFlags.skipGlobal != 0))) {
minDelay = (minDelay == null
? methodWait
: math.min(minDelay, methodWait));
: (minDelay > methodWait ? methodWait : minDelay));
continue;
}
}
Expand Down Expand Up @@ -501,17 +500,23 @@ class API {
final url = request.useAuth ? domain : noAuthDomain;
final beforeSentMethodTime = lastRequest(methodId: request.methodId);
final beforeSentTime = lastRequest();
final methodId = request.methodId;

try {
request._isProcessingNeeded = false;
var inLine = (request.settings & APIFlags.skip == 0) &&
(request.settings & APIFlags.skipGlobal == 0);
_lastRequest = DateTime.now();
_lastRequests[request.methodId] = DateTime.now();
if (inLine) {
_methodBusy[request.methodId] = true;

if (methodId != null) {
_lastRequests[methodId] = DateTime.now();
if (inLine) {
_methodBusy[methodId] = true;
}
}

final requestUrl = '$url${request.method}';
final requestUrl = url.replace(
pathSegments: [...url.pathSegments, ...request.method.split('/')]);
preprocessRequest(request);
if (request.useAuth) authAttacher(request);

Expand All @@ -536,15 +541,15 @@ class API {

final stamp = DateTime.now();
_lastRequest = stamp;
_lastRequests[request.methodId] = stamp;
if (methodId != null) _lastRequests[methodId] = stamp;

if (inLine) {
_methodBusy[request.methodId] = false;
if (methodId != null) _methodBusy[methodId] = false;
}
request._completer.complete(resolver);
} on APIError catch (e) {
_lastRequest = beforeSentTime;
_lastRequests[request.methodId] = beforeSentMethodTime;
if (methodId != null) _lastRequests[methodId] = beforeSentMethodTime;

if ((e.isFloodError && request.settings & APIFlags.resendOnFlood > 0) ||
request.settings & APIFlags.resend > 0) {
Expand All @@ -554,18 +559,19 @@ class API {
}
} catch (e) {
_lastRequest = beforeSentTime;
_lastRequests[request.methodId] = beforeSentMethodTime;
if (methodId != null) _lastRequests[methodId] = beforeSentMethodTime;

request._completer.completeError(e);
rethrow;
}

_methodBusy[request.methodId] = false;
if (methodId != null) _methodBusy[methodId] = false;
}

/// Attaches credentials to given request
void authAttacher(APIRequest request) {
request.headers['X-Token'] = token;
final localToken = token;
if (localToken != null) request.headers['X-Token'] = localToken;
}

/// Preprocesses given request
Expand Down
9 changes: 6 additions & 3 deletions lib/src/mcc/extensions/emoji.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ extension EmojiMCC on MCC {
static String fallbackEmoji = '💳';

/// Related emoji
String get emoji =>
MCCEmojiDataset.keys.firstWhere((e) => MCCEmojiDataset[e].contains(code),
orElse: () => fallbackEmoji);
String get emoji => MCCEmojiDataset.keys.firstWhere((e) {
final emoji = MCCEmojiDataset[e];

if (emoji == null) return false;
return emoji.contains(code);
}, orElse: () => fallbackEmoji);
}
4 changes: 2 additions & 2 deletions lib/src/mcc/extensions/visuals.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ extension VisualsMCC on MCC {
Map<String, String> get visuals => MCCVisualsDataset[emoji] ?? fallbackVisual;

/// Get possible color for use
String get color => visuals['color'];
String get color => visuals['color'] ?? 'crefit_card';

/// Get Material icon name: https://material.io/icons
String get icon => visuals['icon'];
String get icon => visuals['icon'] ?? '#607d8b';
}
22 changes: 11 additions & 11 deletions lib/src/money.dart
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ class Currency {
/// XXX code to look for
String code,
) {
var upperCode = code.toUpperCase();
var info = Iso4217.firstWhere((currency) => currency['code'] == upperCode,
orElse: () => null);
final upperCode = code.toUpperCase();
final info = Iso4217.firstWhere((currency) => currency['code'] == upperCode,
orElse: () => {});

if (info == null) return UnknownCurrency(code);
if (!info.containsKey('code')) return UnknownCurrency(code);

return Currency(info['code'], info['number'], info['digits']);
}
Expand All @@ -65,10 +65,10 @@ class Currency {
/// ISO-4217 number to look for
int number,
) {
var info = Iso4217.firstWhere((currency) => currency['number'] == number,
orElse: () => null);
final info = Iso4217.firstWhere((currency) => currency['number'] == number,
orElse: () => {});

if (info == null) return UnknownCurrency(number.toString());
if (!info.containsKey('code')) return UnknownCurrency(number.toString());

return Currency(info['code'], info['number'], info['digits']);
}
Expand Down Expand Up @@ -196,7 +196,7 @@ class Money implements Comparable {

/// Accepts main and fractional part of the amount as two integers
factory Money.separated(int integer, int fraction, Currency currency) =>
Money(integer * pow(10, currency.digits) + fraction, currency);
Money(integer * pow(10, currency.digits).floor() + fraction, currency);

/// Constant for zero amount of a [Currency.dummy] currency
static const Money zero = Money(0, Currency.dummy);
Expand All @@ -216,7 +216,7 @@ class Money implements Comparable {
@override
int compareTo(other) {
if (other is! Money) throw Exception('Money can be compared only to Money');
Money second = other;
final second = other;

if (this > second) return 1;
if (this < second) return -1;
Expand Down Expand Up @@ -446,7 +446,7 @@ class CurrencyInfo {
/// Shortcut to create conversion objects with same sell rate and currency rate
factory CurrencyInfo.cross(
Currency currencyA, Currency currencyB, double rateCross,
{MoneyRounding rounding}) =>
{MoneyRounding? rounding}) =>
CurrencyInfo(currencyA, currencyB, rateCross, rateCross,
rounding: rounding);
rounding: rounding!);
}
Loading

0 comments on commit 7327265

Please sign in to comment.