Skip to content

Commit

Permalink
Null-safety support
Browse files Browse the repository at this point in the history
  • Loading branch information
eldadfux committed Apr 21, 2021
1 parent aee8859 commit b7d88ee
Show file tree
Hide file tree
Showing 13 changed files with 101 additions and 88 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## 0.5.0-dev.1

- Upgraded to Null-safety, minimum Dart SDK required 2.12.0 and minimum Flutter SDK version required 2.0.0
- Upgraded all underlying dependencies to null safe version
- All of Avatars service now return Future<Response></Response> instead of String like the Storage getFilePreview, getFileView and getFileDownload
- Upgraded to Null-safety, minimum Dart SDK required 2.12.0
- Upgraded all underlying dependencies to null safe version

## 0.4.0

- Improved code quality
Expand Down
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# Appwrite Flutter SDK

[![pub package](https://img.shields.io/pub/v/appwrite.svg)](https://pub.dartlang.org/packages/appwrite)
![License](https://img.shields.io/github/license/appwrite/sdk-for-flutter.svg?v=1)
![Version](https://img.shields.io/badge/api%20version-0.7.0-blue.svg?v=1)
[![pub package](https://img.shields.io/pub/v/appwrite?style=flat-square.svg)](https://pub.dartlang.org/packages/appwrite)
![License](https://img.shields.io/github/license/appwrite/sdk-for-flutter.svg?style=flat-square)
![Version](https://img.shields.io/badge/api%20version-0.7.0-blue.svg?style=flat-square)
[![Twitter Account](https://img.shields.io/twitter/follow/appwrite_io?color=00acee&label=twitter&style=flat-square)](https://twitter.com/appwrite_io)
[![Discord](https://img.shields.io/discord/564160730845151244?label=discord&style=flat-square)](https://appwrite.io/discord)

**This SDK is compatible with Appwrite server version 0.7.x. For older versions, please check [previous releases](https://github.com/appwrite/sdk-for-flutter/releases).**

Expand All @@ -20,7 +22,7 @@ Add this to your package's `pubspec.yaml` file:

```yml
dependencies:
appwrite: ^0.4.0
appwrite: ^0.5.0-dev.1
```
You can install packages from the command line:
Expand Down
3 changes: 3 additions & 0 deletions example/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name: appwrite_example
environment:
sdk: '>=2.6.0 <3.0.0'
3 changes: 1 addition & 2 deletions lib/appwrite.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import 'dart:io';
import 'dart:convert';
import 'package:universal_html/html.dart' as html;
import 'package:dio/dio.dart';
import 'package:meta/meta.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_web_auth/flutter_web_auth.dart';
import 'package:dio/adapter.dart';
Expand All @@ -14,7 +13,7 @@ import 'package:path_provider/path_provider.dart';
import 'package:package_info_plus/package_info_plus.dart';


export 'package:dio/dio.dart' show Response;
export 'package:dio/dio.dart' show Response, MultipartFile;

part 'client.dart';
part 'enums.dart';
Expand Down
54 changes: 28 additions & 26 deletions lib/client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ part of appwrite;
class Client {
String endPoint;
String type = 'unknown';
Map<String, String> headers;
Map<String, String> config;
Map<String, String>? headers;
late Map<String, String> config;
bool selfSigned;
bool initialized = false;
Dio http;
PersistCookieJar cookieJar;
late PersistCookieJar cookieJar;

Client({this.endPoint = 'https://appwrite.io/v1', this.selfSigned = false, Dio http}) : this.http = http ?? Dio() {
Client({this.endPoint = 'https://appwrite.io/v1', this.selfSigned = false, Dio? http}) : this.http = http ?? Dio() {
// Platform is not supported in web so if web, set type to web automatically and skip Platform check
if(kIsWeb) {
type = 'web';
Expand All @@ -25,12 +25,13 @@ class Client {

this.headers = {
'content-type': 'application/json',
'x-sdk-version': 'appwrite:flutter:0.4.0',
'x-sdk-version': 'appwrite:flutter:0.5.0-dev.1',
};

this.config = {};

assert(endPoint.startsWith(RegExp("http://|https://")), "endPoint $endPoint must start with 'http'");
init();
}

Future<Directory> _getCookiePath() async {
Expand Down Expand Up @@ -66,31 +67,29 @@ class Client {
}

Client addHeader(String key, String value) {
headers[key] = value;
headers![key] = value;

return this;
}

Future init() async {
if(!initialized) {
// if web skip cookie implementation and origin header as those are automatically handled by browsers
if(!kIsWeb) {
// if web skip cookie implementation and origin header as those are automatically handled by browsers
if(!kIsWeb) {
final Directory cookieDir = await _getCookiePath();
cookieJar = new PersistCookieJar(dir:cookieDir.path);
cookieJar = new PersistCookieJar(storage: FileStorage(cookieDir.path));
this.http.interceptors.add(CookieManager(cookieJar));
PackageInfo packageInfo = await PackageInfo.fromPlatform();
addHeader('Origin', 'appwrite-$type://${packageInfo.packageName ?? packageInfo.appName}');
}else{
// if web set httpClientAdapter as BrowserHttpClientAdapter with withCredentials true to make cookies work
addHeader('Origin', 'appwrite-$type://${packageInfo.packageName}');
} else {
// if web set withCredentials true to make cookies work
this.http.options.extra['withCredentials'] = true;
}

this.http.options.baseUrl = this.endPoint;
this.http.options.validateStatus = (status) => status < 400;
}

this.http.options.baseUrl = this.endPoint;
this.http.options.validateStatus = (status) => status! < 400;
}

Future<Response> call(HttpMethod method, {String path = '', Map<String, String> headers = const {}, Map<String, dynamic> params = const {}, ResponseType responseType}) async {
Future<Response> call(HttpMethod method, {String path = '', Map<String, String> headers = const {}, Map<String, dynamic> params = const {}, ResponseType? responseType}) async {
if(selfSigned && !kIsWeb) {
// Allow self signed requests
(http.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (HttpClient client) {
Expand All @@ -99,18 +98,21 @@ class Client {
};
}

await this.init();
if(!initialized) {
await this.init();
}

// Origin is hardcoded for testing
Options options = Options(
headers: {...this.headers, ...headers},
headers: {...this.headers!, ...headers},
method: method.name(),
responseType: responseType
responseType: responseType,
listFormat: ListFormat.multiCompatible
);

try {
if(headers['content-type'] == 'multipart/form-data') {
return await http.request(path, data: FormData.fromMap(params), options: options);
return await http.request(path, data: FormData.fromMap(params, ListFormat.multiCompatible), options: options);
}

if (method == HttpMethod.get) {
Expand All @@ -127,16 +129,16 @@ class Client {
throw AppwriteException(e.message);
}
if(responseType == ResponseType.bytes) {
if(e.response.headers['content-type'].contains('application/json')) {
final res = json.decode(utf8.decode(e.response.data));
if(e.response!.headers['content-type']!.contains('application/json')) {
final res = json.decode(utf8.decode(e.response!.data));
throw AppwriteException(res['message'],res['code'], e.response);
} else {
throw AppwriteException(e.message);
}
}
throw AppwriteException(e.response.data['message'],e.response.data['code'], e.response.data);
throw AppwriteException(e.response!.data['message'],e.response!.data['code'], e.response!.data);
} catch(e) {
throw AppwriteException(e.message);
throw AppwriteException(e.toString());
}
}
}
4 changes: 2 additions & 2 deletions lib/exception.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
part of appwrite;

class AppwriteException implements Exception {
final String message;
final int code;
final String? message;
final int? code;
final dynamic response;

AppwriteException([this.message = "", this.code, this.response]);
Expand Down
30 changes: 15 additions & 15 deletions lib/services/account.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class Account extends Service {
/// login to their new account, you need to create a new [account
/// session](/docs/client/account#accountCreateSession).
///
Future<Response> create({@required String email, @required String password, String name = ''}) {
Future<Response> create({required String email, required String password, String name = ''}) {
final String path = '/account';

final Map<String, dynamic> params = {
Expand Down Expand Up @@ -74,7 +74,7 @@ class Account extends Service {
/// mail is sent. For security measures, user password is required to complete
/// this request.
///
Future<Response> updateEmail({@required String email, @required String password}) {
Future<Response> updateEmail({required String email, required String password}) {
final String path = '/account/email';

final Map<String, dynamic> params = {
Expand Down Expand Up @@ -111,7 +111,7 @@ class Account extends Service {
///
/// Update currently logged in user account name.
///
Future<Response> updateName({@required String name}) {
Future<Response> updateName({required String name}) {
final String path = '/account/name';

final Map<String, dynamic> params = {
Expand All @@ -130,7 +130,7 @@ class Account extends Service {
/// Update currently logged in user password. For validation, user is required
/// to pass the password twice.
///
Future<Response> updatePassword({@required String password, @required String oldPassword}) {
Future<Response> updatePassword({required String password, required String oldPassword}) {
final String path = '/account/password';

final Map<String, dynamic> params = {
Expand Down Expand Up @@ -167,7 +167,7 @@ class Account extends Service {
/// Update currently logged in user account preferences. You can pass only the
/// specific settings you wish to update.
///
Future<Response> updatePrefs({@required Map prefs}) {
Future<Response> updatePrefs({required Map prefs}) {
final String path = '/account/prefs';

final Map<String, dynamic> params = {
Expand All @@ -191,7 +191,7 @@ class Account extends Service {
/// /account/recovery](/docs/client/account#accountUpdateRecovery) endpoint to
/// complete the process.
///
Future<Response> createRecovery({@required String email, @required String url}) {
Future<Response> createRecovery({required String email, required String url}) {
final String path = '/account/recovery';

final Map<String, dynamic> params = {
Expand All @@ -218,7 +218,7 @@ class Account extends Service {
/// the only valid redirect URLs are the ones from domains you have set when
/// adding your platforms in the console interface.
///
Future<Response> updateRecovery({@required String userId, @required String secret, @required String password, @required String passwordAgain}) {
Future<Response> updateRecovery({required String userId, required String secret, required String password, required String passwordAgain}) {
final String path = '/account/recovery';

final Map<String, dynamic> params = {
Expand Down Expand Up @@ -258,7 +258,7 @@ class Account extends Service {
/// Allow the user to login into their account by providing a valid email and
/// password combination. This route will create a new session for the user.
///
Future<Response> createSession({@required String email, @required String password}) {
Future<Response> createSession({required String email, required String password}) {
final String path = '/account/sessions';

final Map<String, dynamic> params = {
Expand Down Expand Up @@ -298,7 +298,7 @@ class Account extends Service {
/// first. Use the success and failure arguments to provide a redirect URL's
/// back to your app when login is completed.
///
Future createOAuth2Session({@required String provider, String success = 'https://appwrite.io/auth/oauth2/success', String failure = 'https://appwrite.io/auth/oauth2/failure', List scopes = const []}) {
Future createOAuth2Session({required String provider, String success = 'https://appwrite.io/auth/oauth2/success', String failure = 'https://appwrite.io/auth/oauth2/failure', List scopes = const []}) {
final String path = '/account/sessions/oauth2/{provider}'.replaceAll(RegExp('{provider}'), provider);

final Map<String, dynamic> params = {
Expand Down Expand Up @@ -332,15 +332,15 @@ class Account extends Service {

if(kIsWeb) {
html.window.location.href = url.toString();
return null;
return Future.value();
}else{

return FlutterWebAuth.authenticate(
url: url.toString(),
callbackUrlScheme: "appwrite-callback-" + client.config['project']
callbackUrlScheme: "appwrite-callback-" + client.config['project']!
).then((value) async {
Uri url = Uri.parse(value);
Cookie cookie = new Cookie(url.queryParameters['key'], url.queryParameters['secret']);
Cookie cookie = new Cookie(url.queryParameters['key']!, url.queryParameters['secret']!);
cookie.domain = Uri.parse(client.endPoint).host;
cookie.httpOnly = true;
cookie.path = '/';
Expand All @@ -358,7 +358,7 @@ class Account extends Service {
/// account sessions across all of their different devices. When using the
/// option id argument, only the session unique ID provider will be deleted.
///
Future<Response> deleteSession({@required String sessionId}) {
Future<Response> deleteSession({required String sessionId}) {
final String path = '/account/sessions/{sessionId}'.replaceAll(RegExp('{sessionId}'), sessionId);

final Map<String, dynamic> params = {
Expand Down Expand Up @@ -388,7 +388,7 @@ class Account extends Service {
/// adding your platforms in the console interface.
///
///
Future<Response> createVerification({@required String url}) {
Future<Response> createVerification({required String url}) {
final String path = '/account/verification';

final Map<String, dynamic> params = {
Expand All @@ -409,7 +409,7 @@ class Account extends Service {
/// to verify the user email ownership. If confirmed this route will return a
/// 200 status code.
///
Future<Response> updateVerification({@required String userId, @required String secret}) {
Future<Response> updateVerification({required String userId, required String secret}) {
final String path = '/account/verification';

final Map<String, dynamic> params = {
Expand Down
12 changes: 6 additions & 6 deletions lib/services/avatars.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class Avatars extends Service {
/// /account/sessions endpoint. Use width, height and quality arguments to
/// change the output settings.
///
Future<Response> getBrowser({@required String code, int width = 100, int height = 100, int quality = 100}) {
Future<Response> getBrowser({required String code, int width = 100, int height = 100, int quality = 100}) {
final String path = '/avatars/browsers/{code}'.replaceAll(RegExp('{code}'), code);

final Map<String, dynamic> params = {
Expand All @@ -34,7 +34,7 @@ class Avatars extends Service {
/// provider you need. Use width, height and quality arguments to change the
/// output settings.
///
Future<Response> getCreditCard({@required String code, int width = 100, int height = 100, int quality = 100}) {
Future<Response> getCreditCard({required String code, int width = 100, int height = 100, int quality = 100}) {
final String path = '/avatars/credit-cards/{code}'.replaceAll(RegExp('{code}'), code);

final Map<String, dynamic> params = {
Expand All @@ -57,7 +57,7 @@ class Avatars extends Service {
/// website URL.
///
///
Future<Response> getFavicon({@required String url}) {
Future<Response> getFavicon({required String url}) {
final String path = '/avatars/favicon';

final Map<String, dynamic> params = {
Expand All @@ -78,7 +78,7 @@ class Avatars extends Service {
/// users. The code argument receives the 2 letter country code. Use width,
/// height and quality arguments to change the output settings.
///
Future<Response> getFlag({@required String code, int width = 100, int height = 100, int quality = 100}) {
Future<Response> getFlag({required String code, int width = 100, int height = 100, int quality = 100}) {
final String path = '/avatars/flags/{code}'.replaceAll(RegExp('{code}'), code);

final Map<String, dynamic> params = {
Expand All @@ -102,7 +102,7 @@ class Avatars extends Service {
/// remote images in your app or in case you want to make sure a 3rd party
/// image is properly served using a TLS protocol.
///
Future<Response> getImage({@required String url, int width = 400, int height = 400}) {
Future<Response> getImage({required String url, int width = 400, int height = 400}) {
final String path = '/avatars/image';

final Map<String, dynamic> params = {
Expand Down Expand Up @@ -156,7 +156,7 @@ class Avatars extends Service {
/// Converts a given plain text to a QR code image. You can use the query
/// parameters to change the size and style of the resulting image.
///
Future<Response> getQR({@required String text, int size = 400, int margin = 1, bool download = false}) {
Future<Response> getQR({required String text, int size = 400, int margin = 1, bool download = false}) {
final String path = '/avatars/qr';

final Map<String, dynamic> params = {
Expand Down
Loading

0 comments on commit b7d88ee

Please sign in to comment.