From 8d2cbc2fb0056cfb820feaa1e24f44bba630de45 Mon Sep 17 00:00:00 2001 From: codenameakshay Date: Sun, 14 Nov 2021 22:46:14 +0530 Subject: [PATCH] replace data service with github service --- lib/model/commit_user.dart | 17 ++ lib/model/commit_user.g.dart | 18 ++ lib/model/create_file.dart | 21 ++ lib/model/create_file.g.dart | 26 +++ lib/model/github_error.dart | 92 +++++++++ lib/model/github_json.dart | 66 +++++++ lib/pages/home_page.dart | 8 +- lib/services/data_service.dart | 64 +++--- lib/services/file_picker_service.dart | 8 +- lib/services/github_service.dart | 181 +++++++++++++++++ lib/services/locator.dart | 4 +- pubspec.lock | 271 +++++++++++++++++++++++++- pubspec.yaml | 5 +- 13 files changed, 735 insertions(+), 46 deletions(-) create mode 100644 lib/model/commit_user.dart create mode 100644 lib/model/commit_user.g.dart create mode 100644 lib/model/create_file.dart create mode 100644 lib/model/create_file.g.dart create mode 100644 lib/model/github_error.dart create mode 100644 lib/model/github_json.dart create mode 100644 lib/services/github_service.dart diff --git a/lib/model/commit_user.dart b/lib/model/commit_user.dart new file mode 100644 index 0000000..39e1e06 --- /dev/null +++ b/lib/model/commit_user.dart @@ -0,0 +1,17 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'commit_user.g.dart'; + +/// Model class for a committer of a commit. +@JsonSerializable() +class CommitUser { + CommitUser(this.name, this.email); + + final String? name; + final String? email; + + factory CommitUser.fromJson(Map input) => + _$CommitUserFromJson(input); + + Map toJson() => _$CommitUserToJson(this); +} diff --git a/lib/model/commit_user.g.dart b/lib/model/commit_user.g.dart new file mode 100644 index 0000000..90abe7b --- /dev/null +++ b/lib/model/commit_user.g.dart @@ -0,0 +1,18 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'commit_user.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +CommitUser _$CommitUserFromJson(Map json) => CommitUser( + json['name'] as String?, + json['email'] as String?, + ); + +Map _$CommitUserToJson(CommitUser instance) => + { + 'name': instance.name, + 'email': instance.email, + }; diff --git a/lib/model/create_file.dart b/lib/model/create_file.dart new file mode 100644 index 0000000..ca02e24 --- /dev/null +++ b/lib/model/create_file.dart @@ -0,0 +1,21 @@ +import 'package:json_annotation/json_annotation.dart'; +import 'package:odin/model/commit_user.dart'; + +part 'create_file.g.dart'; + +@JsonSerializable() +class CreateFile { + CreateFile( + {this.path, this.content, this.message, this.branch, this.committer}); + + String? path; + String? message; + String? content; + String? branch; + CommitUser? committer; + + factory CreateFile.fromJson(Map json) => + _$CreateFileFromJson(json); + + Map toJson() => _$CreateFileToJson(this); +} diff --git a/lib/model/create_file.g.dart b/lib/model/create_file.g.dart new file mode 100644 index 0000000..8db5406 --- /dev/null +++ b/lib/model/create_file.g.dart @@ -0,0 +1,26 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'create_file.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +CreateFile _$CreateFileFromJson(Map json) => CreateFile( + path: json['path'] as String?, + content: json['content'] as String?, + message: json['message'] as String?, + branch: json['branch'] as String?, + committer: json['committer'] == null + ? null + : CommitUser.fromJson(json['committer'] as Map), + ); + +Map _$CreateFileToJson(CreateFile instance) => + { + 'path': instance.path, + 'message': instance.message, + 'content': instance.content, + 'branch': instance.branch, + 'committer': instance.committer, + }; diff --git a/lib/model/github_error.dart b/lib/model/github_error.dart new file mode 100644 index 0000000..3a1a51c --- /dev/null +++ b/lib/model/github_error.dart @@ -0,0 +1,92 @@ +/// Error Generated by [GitHub] +class GitHubError implements Exception { + final String? message; + final String? apiUrl; + final Object? source; + + const GitHubError(this.message, {this.apiUrl, this.source}); + + @override + String toString() => 'GitHub Error: $message'; +} + +class NotReady extends GitHubError { + const NotReady(String path) + : super( + 'Not ready. Try again later', + apiUrl: path, + ); +} + +/// GitHub Entity was not found +class NotFound extends GitHubError { + const NotFound( + String msg, + ) : super(msg); +} + +class BadRequest extends GitHubError { + const BadRequest([String? msg = 'Not Found']) : super(msg); +} + +/// GitHub Repository was not found +class RepositoryNotFound extends NotFound { + const RepositoryNotFound(String repo) : super('Repository Not Found: $repo'); +} + +/// Release not found +class ReleaseNotFound extends NotFound { + const ReleaseNotFound.fromTagName(String? tagName) + : super('Release for tagName $tagName Not Found.'); +} + +/// GitHub User was not found +class UserNotFound extends NotFound { + const UserNotFound(String user) : super('User Not Found: $user'); +} + +/// GitHub Organization was not found +class OrganizationNotFound extends NotFound { + const OrganizationNotFound(String? organization) + : super('Organization Not Found: $organization'); +} + +/// GitHub Team was not found +class TeamNotFound extends NotFound { + const TeamNotFound(int id) : super('Team Not Found: $id'); +} + +/// Access was forbidden to a resource +class AccessForbidden extends GitHubError { + const AccessForbidden() : super('Access Forbidden'); +} + +/// Client hit the rate limit. +class RateLimitHit extends GitHubError { + const RateLimitHit() : super('Rate Limit Hit'); +} + +/// A GitHub Server Error +class ServerError extends GitHubError { + ServerError(int statusCode, String? message) + : super('${message ?? 'Server Error'} ($statusCode)'); +} + +/// An Unknown Error +class UnknownError extends GitHubError { + const UnknownError([String? message]) : super(message ?? 'Unknown Error'); +} + +/// GitHub Client was not authenticated +class NotAuthenticated extends GitHubError { + const NotAuthenticated() : super('Client not Authenticated'); +} + +class InvalidJSON extends BadRequest { + const InvalidJSON([String? message = 'Invalid JSON']) : super(message); +} + +class ValidationFailed extends GitHubError { + const ValidationFailed([String message = 'Validation Failed']) + : super(message); +} diff --git a/lib/model/github_json.dart b/lib/model/github_json.dart new file mode 100644 index 0000000..12c542b --- /dev/null +++ b/lib/model/github_json.dart @@ -0,0 +1,66 @@ +import 'dart:convert'; + +/// Creates a Model Object from the JSON [input] +typedef JSONConverter = T Function(S input); + +final RegExp githubDateRemoveRegExp = RegExp(r'\.\d*'); +String? dateToGitHubIso8601(DateTime? date) { + if (date == null) { + return null; + } + // Regex removes the milliseconds. + return date.toUtc().toIso8601String().replaceAll(githubDateRemoveRegExp, ''); +} + +/// Internal class for Json encoding +/// that should be used instead of `dart:convert`. +/// +/// It contains methods that ensures that converted Json +/// will work with the GitHub API. +class GitHubJson { + const GitHubJson._(); + + /// Called only if an object is of a non primitive type. + /// + /// If [object] is a [DateTime], it converts it to a String whose format is compatible with the API. + /// Else, it uses the default behavior of [JsonEncoder] which is to call `toJson` method onto [object]. + /// + /// If [object] is not a [DateTime] and don't have a `toJson` method, an exception will be thrown + /// but handled by [JsonEncoder]. + /// Do not catch it. + static dynamic _toEncodable(dynamic object) { + if (object is DateTime) { + return dateToGitHubIso8601(object); + } + // `toJson` could return a [Map] or a [List], + // so we have to delete null values in them. + return _checkObject(object.toJson()); + } + + /// Encodes [object] to a Json String compatible with the GitHub API. + /// It should be used instead of `jsonEncode`. + /// + /// Equivalent to `jsonEncode` except that + /// it converts [DateTime] to a proper String for the GitHub API, + /// and it also deletes keys associated with null values in maps before converting them. + /// + /// The obtained String can be decoded using `jsonDecode`. + static String encode(Object object, {String? indent}) { + final encoder = JsonEncoder.withIndent(indent, _toEncodable); + return encoder.convert(_checkObject(object)); + } + + /// Deletes keys associated with null values + /// in every map contained in [object]. + static dynamic _checkObject(dynamic object) { + if (object is Map) { + return Map.fromEntries(object.entries + .where((e) => e.value != null) + .map((e) => MapEntry(e.key, _checkObject(e.value)))); + } + if (object is List) { + return object.map(_checkObject).toList(); + } + return object; + } +} diff --git a/lib/pages/home_page.dart b/lib/pages/home_page.dart index 21f4cdf..88ef5d0 100644 --- a/lib/pages/home_page.dart +++ b/lib/pages/home_page.dart @@ -6,6 +6,7 @@ import 'package:odin/painters/odin_logo_painter.dart'; import 'package:odin/painters/ripple_painter.dart'; import 'package:odin/services/data_service.dart'; import 'package:odin/services/file_picker_service.dart'; +import 'package:odin/services/github_service.dart'; import 'package:odin/services/locator.dart'; import 'package:odin/services/zip_service.dart'; import 'package:odin/widgets/window_top_bar.dart'; @@ -30,7 +31,8 @@ class _HomePageState extends State bool _dragging = false; bool _loading = false; String? _fileLink; - final _ds = locator(); + // final _ds = locator(); + final _gs = locator(); final _zs = locator(); final _fps = locator(); @override @@ -96,9 +98,9 @@ class _HomePageState extends State detail.urls.map((e) => File(e.toFilePath())).toList(); final zippedFile = await _zs.zipFile(fileToZips: fileToZips); - _fileLink = await _ds.uploadFileAnonymous(zippedFile); + _fileLink = await _gs.uploadFileAnonymous(zippedFile); } else { - _fileLink = await _ds.uploadFileAnonymous( + _fileLink = await _gs.uploadFileAnonymous( File(detail.urls.first.toFilePath())); } } diff --git a/lib/services/data_service.dart b/lib/services/data_service.dart index a9fe01f..c7448d0 100644 --- a/lib/services/data_service.dart +++ b/lib/services/data_service.dart @@ -1,35 +1,35 @@ -import 'dart:convert'; -import 'dart:io'; +// import 'dart:convert'; +// import 'dart:io'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; -import 'package:github/github.dart'; -import 'package:intl/intl.dart'; -import 'package:odin/services/locator.dart'; -import 'package:odin/services/random_service.dart'; -import 'package:odin/services/shortner_service.dart'; -import 'package:path/path.dart' as path; +// import 'package:flutter_dotenv/flutter_dotenv.dart'; +// import 'package:github/github.dart'; +// import 'package:intl/intl.dart'; +// import 'package:odin/services/locator.dart'; +// import 'package:odin/services/random_service.dart'; +// import 'package:odin/services/shortner_service.dart'; +// import 'package:path/path.dart' as path; -class DataService { - final ShortnerService _shortnerService = locator(); - final RandomService _randomService = locator(); - final _env = dotenv.env; - final _gh = - GitHub(auth: Authentication.withToken(dotenv.env['GITHUB_TOKEN'])); +// class DataService { +// final ShortnerService _shortnerService = locator(); +// final RandomService _randomService = locator(); +// final _env = dotenv.env; +// final _gh = +// GitHub(auth: Authentication.withToken(dotenv.env['GITHUB_TOKEN'])); - Future uploadFileAnonymous(File file) async { - final uploadTime = DateFormat('dd-MM-yyyy hh:mm:ss').format(DateTime.now()); - final _ghFile = await _gh.repositories.createFile( - RepositorySlug( - _env['GITHUB_USERNAME'] ?? '', _env['GITHUB_REPO_NAME'] ?? ''), - CreateFile( - content: base64Encode(file.readAsBytesSync()), - message: "☄️ -> '${path.basename(file.path)}' | $uploadTime", - path: - "${_randomService.getRandomString(15)}/${path.basename(file.path)}", - ), - ); - final _downloadLink = await _shortnerService.shortUrl( - url: _ghFile.content?.downloadUrl ?? ''); - return _downloadLink ?? ''; - } -} +// Future uploadFileAnonymous(File file) async { +// final uploadTime = DateFormat('dd-MM-yyyy hh:mm:ss').format(DateTime.now()); +// final _ghFile = await _gh.repositories.createFile( +// RepositorySlug( +// _env['GITHUB_USERNAME'] ?? '', _env['GITHUB_REPO_NAME'] ?? ''), +// CreateFile( +// content: base64Encode(file.readAsBytesSync()), +// message: "☄️ -> '${path.basename(file.path)}' | $uploadTime", +// path: +// "${_randomService.getRandomString(15)}/${path.basename(file.path)}", +// ), +// ); +// final _downloadLink = await _shortnerService.shortUrl( +// url: _ghFile.content?.downloadUrl ?? ''); +// return _downloadLink ?? ''; +// } +// } diff --git a/lib/services/file_picker_service.dart b/lib/services/file_picker_service.dart index 7a48921..14d2493 100644 --- a/lib/services/file_picker_service.dart +++ b/lib/services/file_picker_service.dart @@ -2,11 +2,13 @@ import 'dart:io'; import 'package:file_picker/file_picker.dart'; import 'package:odin/services/data_service.dart'; +import 'package:odin/services/github_service.dart'; import 'package:odin/services/locator.dart'; import 'package:odin/services/zip_service.dart'; class FilepickerService { - final _dataService = locator(); + // final _dataService = locator(); + final _githubService = locator(); final _zipService = locator(); Future getFiles() async { @@ -18,9 +20,9 @@ class FilepickerService { final int length = files.length; if (length > 1) { final zippedFile = await _zipService.zipFile(fileToZips: files); - _path = await _dataService.uploadFileAnonymous(zippedFile); + _path = await _githubService.uploadFileAnonymous(zippedFile); } else { - _path = await _dataService.uploadFileAnonymous(files.first); + _path = await _githubService.uploadFileAnonymous(files.first); } } else { // User canceled the picker diff --git a/lib/services/github_service.dart b/lib/services/github_service.dart new file mode 100644 index 0000000..ff45056 --- /dev/null +++ b/lib/services/github_service.dart @@ -0,0 +1,181 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:intl/intl.dart'; +import 'package:odin/model/create_file.dart'; +import 'package:odin/model/github_error.dart'; +import 'package:odin/model/github_json.dart'; +import 'package:odin/services/locator.dart'; +import 'package:odin/services/random_service.dart'; +import 'package:odin/services/shortner_service.dart'; +import 'package:http/http.dart' as http; +import 'package:path/path.dart' as path; + +class GithubService { + final ShortnerService _shortnerService = locator(); + final RandomService _randomService = locator(); + final _env = dotenv.env; + + Future uploadFileAnonymous(File file) async { + final uploadTime = DateFormat('dd-MM-yyyy hh:mm:ss').format(DateTime.now()); + final createFile = CreateFile( + content: base64Encode(file.readAsBytesSync()), + message: "☄️ -> '${path.basename(file.path)}' | $uploadTime", + path: "${_randomService.getRandomString(15)}/${path.basename(file.path)}", + ); + final response = await request( + 'PUT', + '/repos/${_env['GITHUB_USERNAME']}/${_env['GITHUB_REPO_NAME']}/contents/${createFile.path}', + body: GitHubJson.encode(createFile), + ); + + final _downloadLink = await _shortnerService.shortUrl( + url: jsonDecode(response.body)["content"]["download_url"] ?? ''); + return _downloadLink ?? ''; + } + + Future request( + String method, + String path, { + Map? headers, + Map? params, + dynamic body, + int? statusCode, + void Function(http.Response response)? fail, + String? preview, + }) async { + http.Client client = http.Client(); + headers ??= {}; + + if (preview != null) { + headers['Accept'] = preview; + } + + headers.putIfAbsent('Authorization', () => 'token ${_env['GITHUB_TOKEN']}'); + + if (method == 'PUT' && body == null) { + headers.putIfAbsent('Content-Length', () => '0'); + } + + var queryString = ''; + + if (params != null) { + queryString = buildQueryString(params); + } + + final url = StringBuffer(); + + if (path.startsWith('http://') || path.startsWith('https://')) { + url.write(path); + url.write(queryString); + } else { + url.write('https://api.github.com'); + if (!path.startsWith('/')) { + url.write('/'); + } + url.write(path); + url.write(queryString); + } + + final request = http.Request(method, Uri.parse(url.toString())); + request.headers.addAll(headers); + if (body != null) { + if (body is List) { + request.bodyBytes = body; + } else { + request.body = body.toString(); + } + } + + final streamedResponse = await client.send(request); + + final response = await http.Response.fromStream(streamedResponse); + + if (statusCode != null && statusCode != response.statusCode) { + if (fail != null) { + fail(response); + } + handleStatusCode(response); + } else { + return response; + } + + throw const UnknownError(); + } + + void handleStatusCode(http.Response response) { + String? message; + List>? errors; + if (response.headers['content-type']!.contains('application/json')) { + final json = jsonDecode(response.body); + message = json['message']; + if (json['errors'] != null) { + try { + errors = List>.from(json['errors']); + } catch (_) { + errors = [ + {'code': json['errors'].toString()} + ]; + } + } + } + switch (response.statusCode) { + case 404: + throw const NotFound('Requested Resource was Not Found'); + case 401: + throw const AccessForbidden(); + case 400: + if (message == 'Problems parsing JSON') { + throw InvalidJSON(message); + } else if (message == 'Body should be a JSON Hash') { + throw InvalidJSON(message); + } else { + throw const BadRequest(); + } + case 422: + final buff = StringBuffer(); + buff.writeln(); + buff.writeln(' Message: $message'); + if (errors != null) { + buff.writeln(' Errors:'); + for (final error in errors) { + final resource = error['resource']; + final field = error['field']; + final code = error['code']; + buff + ..writeln(' Resource: $resource') + ..writeln(' Field $field') + ..write(' Code: $code'); + } + } + throw ValidationFailed(buff.toString()); + case 500: + case 502: + case 504: + throw ServerError(response.statusCode, message); + } + throw UnknownError(message); + } + + String buildQueryString(Map params) { + final queryString = StringBuffer(); + + if (params.isNotEmpty && !params.values.every((value) => value == null)) { + queryString.write('?'); + } + + var i = 0; + for (final key in params.keys) { + i++; + if (params[key] == null) { + continue; + } + queryString.write('$key=${Uri.encodeComponent(params[key].toString())}'); + if (i != params.keys.length) { + queryString.write('&'); + } + } + return queryString.toString(); + } +} diff --git a/lib/services/locator.dart b/lib/services/locator.dart index 7c7e256..ba56c72 100644 --- a/lib/services/locator.dart +++ b/lib/services/locator.dart @@ -1,6 +1,7 @@ import 'package:get_it/get_it.dart'; import 'package:odin/services/data_service.dart'; import 'package:odin/services/file_picker_service.dart'; +import 'package:odin/services/github_service.dart'; import 'package:odin/services/random_service.dart'; import 'package:odin/services/shortner_service.dart'; import 'package:odin/services/zip_service.dart'; @@ -12,7 +13,8 @@ GetIt locator = GetIt.instance; Future setupLocator() async { Stopwatch stopwatch = Stopwatch()..start(); // locator.registerFactory(() => CurrentDataNotifier()); - locator.registerLazySingleton(() => DataService()); + // locator.registerLazySingleton(() => DataService()); + locator.registerLazySingleton(() => GithubService()); locator.registerLazySingleton(() => ShortnerService()); locator.registerLazySingleton(() => RandomService()); locator.registerLazySingleton(() => ZipService()); diff --git a/pubspec.lock b/pubspec.lock index e526821..a9eb5e0 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,6 +1,20 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + url: "https://pub.dartlang.org" + source: hosted + version: "30.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + url: "https://pub.dartlang.org" + source: hosted + version: "2.7.0" archive: dependency: "direct main" description: @@ -8,6 +22,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.1.6" + args: + dependency: transitive + description: + name: args + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.0" async: dependency: transitive description: @@ -57,6 +78,62 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" + build: + dependency: transitive + description: + name: build + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.1" + build_config: + dependency: transitive + description: + name: build_config + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + build_daemon: + dependency: transitive + description: + name: build_daemon + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.4" + build_runner: + dependency: "direct dev" + description: + name: build_runner + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.5" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + url: "https://pub.dartlang.org" + source: hosted + version: "7.2.2" + built_collection: + dependency: transitive + description: + name: built_collection + url: "https://pub.dartlang.org" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + url: "https://pub.dartlang.org" + source: hosted + version: "8.1.3" characters: dependency: transitive description: @@ -71,6 +148,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.1" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + cli_util: + dependency: transitive + description: + name: cli_util + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.5" clock: dependency: transitive description: @@ -78,6 +169,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.0" + code_builder: + dependency: transitive + description: + name: code_builder + url: "https://pub.dartlang.org" + source: hosted + version: "4.1.0" collection: dependency: transitive description: @@ -85,6 +183,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.15.0" + convert: + dependency: transitive + description: + name: convert + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" crypto: dependency: transitive description: @@ -99,6 +204,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.4" + dart_style: + dependency: transitive + description: + name: dart_style + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.0" desktop_drop: dependency: "direct main" description: @@ -141,6 +253,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "4.2.3" + fixnum: + dependency: transitive + description: + name: fixnum + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" flutter: dependency: "direct main" description: flutter @@ -177,6 +296,13 @@ packages: description: flutter source: sdk version: "0.0.0" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.2" get_it: dependency: "direct main" description: @@ -184,20 +310,34 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "7.2.0" - github: - dependency: "direct main" + glob: + dependency: transitive description: - name: github + name: glob url: "https://pub.dartlang.org" source: hosted - version: "8.2.5" - http: + version: "2.0.2" + graphs: dependency: transitive + description: + name: graphs + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + http: + dependency: "direct main" description: name: http url: "https://pub.dartlang.org" source: hosted version: "0.13.4" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" http_parser: dependency: transitive description: @@ -212,6 +352,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.17.0" + io: + dependency: transitive + description: + name: io + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.3" js: dependency: transitive description: @@ -220,12 +367,19 @@ packages: source: hosted version: "0.6.3" json_annotation: - dependency: transitive + dependency: "direct main" description: name: json_annotation url: "https://pub.dartlang.org" source: hosted version: "4.3.0" + json_serializable: + dependency: "direct dev" + description: + name: json_serializable + url: "https://pub.dartlang.org" + source: hosted + version: "6.0.1" lints: dependency: transitive description: @@ -240,6 +394,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.0" + logging: + dependency: transitive + description: + name: logging + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" matcher: dependency: transitive description: @@ -254,6 +415,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.7.0" + mime: + dependency: transitive + description: + name: mime + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" nested: dependency: transitive description: @@ -261,6 +429,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.0" + package_config: + dependency: transitive + description: + name: package_config + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.2" path: dependency: "direct main" description: @@ -317,6 +492,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.2" + pool: + dependency: transitive + description: + name: pool + url: "https://pub.dartlang.org" + source: hosted + version: "1.5.0" process: dependency: transitive description: @@ -331,11 +513,53 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "6.0.1" + pub_semver: + dependency: transitive + description: + name: pub_semver + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + shelf: + dependency: transitive + description: + name: shelf + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" sky_engine: dependency: transitive description: flutter source: sdk version: "0.0.99" + source_gen: + dependency: transitive + description: + name: source_gen + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.1" + source_helper: + dependency: transitive + description: + name: source_helper + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.0" source_span: dependency: transitive description: @@ -357,6 +581,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" + stream_transform: + dependency: transitive + description: + name: stream_transform + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" string_scanner: dependency: transitive description: @@ -378,6 +609,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.4.2" + timing: + dependency: transitive + description: + name: timing + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" typed_data: dependency: transitive description: @@ -434,6 +672,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" + watcher: + dependency: transitive + description: + name: watcher + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" win32: dependency: transitive description: @@ -448,6 +700,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.2.0" + yaml: + dependency: transitive + description: + name: yaml + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.0" sdks: dart: ">=2.14.0 <3.0.0" flutter: ">=2.5.0" diff --git a/pubspec.yaml b/pubspec.yaml index 80472d4..f1a6b96 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -37,8 +37,9 @@ dependencies: sdk: flutter flutter_dotenv: ^5.0.2 get_it: ^7.2.0 - github: ^8.2.5 + http: ^0.13.4 intl: ^0.17.0 + json_annotation: ^4.3.0 logger: ^1.1.0 path: ^1.8.0 path_provider: ^2.0.6 @@ -46,9 +47,11 @@ dependencies: url_launcher: ^6.0.12 dev_dependencies: + build_runner: ^2.1.5 flutter_lints: ^1.0.0 flutter_test: sdk: flutter + json_serializable: ^6.0.1 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec