From 230c638c6e08bb55c4d35e25d03012d79356296a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Sat, 3 May 2025 13:18:55 +0100 Subject: [PATCH 01/30] :construction: initial refactor --- .../example/talker_http_logger_example.dart | 26 +-- .../lib/http_error_log.dart | 46 +++++ .../lib/http_request_log.dart | 56 ++++++ .../lib/http_response_log.dart | 46 +++++ .../lib/talker_http_logger.dart | 170 +----------------- .../lib/talker_http_logger_interceptor.dart | 62 +++++++ 6 files changed, 229 insertions(+), 177 deletions(-) create mode 100644 packages/talker_http_logger/lib/http_error_log.dart create mode 100644 packages/talker_http_logger/lib/http_request_log.dart create mode 100644 packages/talker_http_logger/lib/http_response_log.dart create mode 100644 packages/talker_http_logger/lib/talker_http_logger_interceptor.dart diff --git a/packages/talker_http_logger/example/talker_http_logger_example.dart b/packages/talker_http_logger/example/talker_http_logger_example.dart index 75ff2dd3c..aa6d6cf0f 100644 --- a/packages/talker_http_logger/example/talker_http_logger_example.dart +++ b/packages/talker_http_logger/example/talker_http_logger_example.dart @@ -1,17 +1,23 @@ import 'package:http_interceptor/http_interceptor.dart'; import 'package:talker_http_logger/talker_http_logger.dart'; -import 'package:talker_http_logger/talker_http_logger_settings.dart'; void main(List args) async { - final client = InterceptedClient.build(interceptors: [ - TalkerHttpLogger( + final InterceptedClient client = InterceptedClient.build( + interceptors: [ + TalkerHttpLogger( settings: TalkerHttpLoggerSettings( - hiddenHeaders: {'Authorization'})), - ]); + hiddenHeaders: {'Authorization'}, + ), + ), + ], + ); - await client.get("https://google.com".toUri(), headers: { - "firstHeader": "firstHeaderValue", - "authorization": "bearer super_secret_token", - "lastHeader": "lastHeaderValue", - }); + await client.get( + Uri.https("google.com"), + headers: { + "firstHeader": "firstHeaderValue", + "authorization": "bearer super_secret_token", + "lastHeader": "lastHeaderValue", + }, + ); } diff --git a/packages/talker_http_logger/lib/http_error_log.dart b/packages/talker_http_logger/lib/http_error_log.dart new file mode 100644 index 000000000..d04710493 --- /dev/null +++ b/packages/talker_http_logger/lib/http_error_log.dart @@ -0,0 +1,46 @@ +import 'dart:convert' show JsonEncoder; + +import 'package:http_interceptor/http_interceptor.dart'; +import 'package:talker/talker.dart'; +import 'package:talker_http_logger/talker_http_logger_settings.dart'; + +class HttpErrorLog extends TalkerLog { + HttpErrorLog( + super.title, { + required this.response, + this.settings = const TalkerHttpLoggerSettings(), + }); + + final BaseResponse response; + final TalkerHttpLoggerSettings settings; + + static const JsonEncoder _encoder = JsonEncoder.withIndent(' '); + + @override + AnsiPen get pen => AnsiPen()..red(); + + @override + String get key => TalkerLogType.httpError.key; + + @override + String generateTextMessage({ + TimeFormat timeFormat = TimeFormat.timeAndSeconds, + }) { + final StringBuffer msg = StringBuffer(); + msg.write('[$title]'); + msg.write(' [${response.request?.method}]'); + msg.writeln(' $message'); + + msg.writeln('Status: ${response.statusCode}'); + + try { + if (response.request?.headers.isNotEmpty ?? false) { + msg.write('Headers: ${_encoder.convert(response.request?.headers)}'); + } + } catch (_) { + // TODO: add handling can`t convert + } + + return msg.toString().trimRight(); + } +} diff --git a/packages/talker_http_logger/lib/http_request_log.dart b/packages/talker_http_logger/lib/http_request_log.dart new file mode 100644 index 000000000..8d7974628 --- /dev/null +++ b/packages/talker_http_logger/lib/http_request_log.dart @@ -0,0 +1,56 @@ +import 'dart:convert' show JsonEncoder; + +import 'package:http_interceptor/http_interceptor.dart'; +import 'package:talker/talker.dart'; +import 'package:talker_http_logger/talker_http_logger_settings.dart'; + +class HttpRequestLog extends TalkerLog { + HttpRequestLog( + super.title, { + required this.request, + this.settings = const TalkerHttpLoggerSettings(), + }); + + final BaseRequest request; + final TalkerHttpLoggerSettings settings; + + static const JsonEncoder _encoder = JsonEncoder.withIndent(' '); + static const String _hiddenValue = '*****'; + + @override + AnsiPen get pen => (AnsiPen()..xterm(219)); + + @override + String get key => TalkerLogType.httpRequest.key; + + @override + String generateTextMessage({ + TimeFormat timeFormat = TimeFormat.timeAndSeconds, + }) { + final StringBuffer msg = StringBuffer(); + msg.write('[$title]'); + msg.write(' [${request.method}]'); + msg.writeln(' $message'); + + final Map headers = {...request.headers}; + + try { + if (headers.isNotEmpty) { + if (settings.hiddenHeaders.isNotEmpty) { + headers.updateAll((String key, String value) { + return settings.hiddenHeaders + .map((v) => v.toLowerCase()) + .contains(key.toLowerCase()) + ? _hiddenValue + : value; + }); + } + msg.write('Headers: ${_encoder.convert(headers)}'); + } + } catch (_) { + // TODO: add handling can`t convert + } + + return msg.toString().trimRight(); + } +} diff --git a/packages/talker_http_logger/lib/http_response_log.dart b/packages/talker_http_logger/lib/http_response_log.dart new file mode 100644 index 000000000..84ad92a5c --- /dev/null +++ b/packages/talker_http_logger/lib/http_response_log.dart @@ -0,0 +1,46 @@ +import 'dart:convert' show JsonEncoder; + +import 'package:http_interceptor/http_interceptor.dart'; +import 'package:talker/talker.dart'; +import 'package:talker_http_logger/talker_http_logger_settings.dart'; + +class HttpResponseLog extends TalkerLog { + HttpResponseLog( + super.title, { + required this.response, + this.settings = const TalkerHttpLoggerSettings(), + }); + + final BaseResponse response; + final TalkerHttpLoggerSettings settings; + + static const JsonEncoder _encoder = JsonEncoder.withIndent(' '); + + @override + AnsiPen get pen => (AnsiPen()..xterm(46)); + + @override + String get key => TalkerLogType.httpResponse.key; + + @override + String generateTextMessage({ + TimeFormat timeFormat = TimeFormat.timeAndSeconds, + }) { + final StringBuffer msg = StringBuffer(); + msg.write('[$title]'); + msg.write(' [${response.request?.method}]'); + msg.write(' $message'); + + msg.writeln('Status: ${response.statusCode}'); + + try { + if (response.request?.headers.isNotEmpty ?? false) { + msg.write('Headers: ${_encoder.convert(response.request?.headers)}'); + } + } catch (_) { + // TODO: add handling can`t convert + } + + return msg.toString().trimRight(); + } +} diff --git a/packages/talker_http_logger/lib/talker_http_logger.dart b/packages/talker_http_logger/lib/talker_http_logger.dart index dcc5a20d8..118e24256 100644 --- a/packages/talker_http_logger/lib/talker_http_logger.dart +++ b/packages/talker_http_logger/lib/talker_http_logger.dart @@ -1,168 +1,4 @@ -library talker_http_logger; +library; -import 'dart:convert'; - -import 'package:http_interceptor/http_interceptor.dart'; -import 'package:talker/talker.dart'; -import 'package:talker_http_logger/talker_http_logger_settings.dart'; - -class TalkerHttpLogger extends InterceptorContract { - TalkerHttpLogger( - {Talker? talker, this.settings = const TalkerHttpLoggerSettings()}) { - _talker = talker ?? Talker(); - } - - late Talker _talker; - - /// [TalkerHttpLogger] settings and customization - TalkerHttpLoggerSettings settings; - - @override - Future interceptRequest({ - required BaseRequest request, - }) async { - final message = '${request.url}'; - _talker.logCustom( - HttpRequestLog(message, request: request, settings: settings)); - return request; - } - - @override - Future interceptResponse({ - required BaseResponse response, - }) async { - final message = '${response.request?.url}'; - - if (response.statusCode >= 400 && response.statusCode < 600) { - _talker.logCustom(HttpErrorLog(message, response: response)); - } else { - _talker.logCustom(HttpResponseLog(message, response: response)); - } - - return response; - } -} - -const encoder = JsonEncoder.withIndent(' '); -const _hiddenValue = '*****'; - -class HttpRequestLog extends TalkerLog { - HttpRequestLog( - String title, { - required this.request, - this.settings = const TalkerHttpLoggerSettings(), - }) : super(title); - - final BaseRequest request; - - final TalkerHttpLoggerSettings settings; - - @override - AnsiPen get pen => (AnsiPen()..xterm(219)); - - @override - String get key => TalkerLogType.httpRequest.key; - - @override - String generateTextMessage( - {TimeFormat timeFormat = TimeFormat.timeAndSeconds}) { - var msg = '[$title] [${request.method}] $message'; - - final headers = Map.from(request.headers); - - try { - if (headers.isNotEmpty) { - if (settings.hiddenHeaders.isNotEmpty) { - headers.updateAll((key, value) { - return settings.hiddenHeaders - .map((v) => v.toLowerCase()) - .contains(key.toLowerCase()) - ? _hiddenValue - : value; - }); - } - final prettyHeaders = encoder.convert(headers); - msg += '\nHeaders: $prettyHeaders'; - } - } catch (_) { - // TODO: add handling can`t convert - } - return msg; - } -} - -class HttpResponseLog extends TalkerLog { - HttpResponseLog( - String title, { - required this.response, - this.settings = const TalkerHttpLoggerSettings(), - }) : super(title); - - final BaseResponse response; - - final TalkerHttpLoggerSettings settings; - - @override - AnsiPen get pen => (AnsiPen()..xterm(46)); - - @override - String get key => TalkerLogType.httpResponse.key; - - @override - String generateTextMessage( - {TimeFormat timeFormat = TimeFormat.timeAndSeconds}) { - var msg = '[$title] [${response.request?.method}] $message'; - - final headers = response.request?.headers; - - msg += '\nStatus: ${response.statusCode}'; - - try { - if (headers?.isNotEmpty ?? false) { - final prettyHeaders = encoder.convert(headers); - msg += '\nHeaders: $prettyHeaders'; - } - } catch (_) { - // TODO: add handling can`t convert - } - return msg; - } -} - -class HttpErrorLog extends TalkerLog { - HttpErrorLog( - String title, { - required this.response, - this.settings = const TalkerHttpLoggerSettings(), - }) : super(title); - - final BaseResponse response; - - final TalkerHttpLoggerSettings settings; - - @override - AnsiPen get pen => AnsiPen()..red(); - - @override - String get key => TalkerLogType.httpError.key; - - @override - String generateTextMessage( - {TimeFormat timeFormat = TimeFormat.timeAndSeconds}) { - var msg = '[$title] [${response.request?.method}] $message'; - - final headers = response.request?.headers; - - msg += '\nStatus: ${response.statusCode}'; - - try { - if (headers?.isNotEmpty ?? false) { - final prettyHeaders = encoder.convert(headers); - msg += '\nHeaders: $prettyHeaders'; - } - } catch (_) { - // TODO: add handling can`t convert - } - return msg; - } -} +export 'talker_http_logger_interceptor.dart'; +export 'talker_http_logger_settings.dart'; diff --git a/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart b/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart new file mode 100644 index 000000000..85dc28ba1 --- /dev/null +++ b/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart @@ -0,0 +1,62 @@ +import 'package:http_interceptor/http_interceptor.dart'; +import 'package:talker/talker.dart'; +import 'package:talker_http_logger/http_error_log.dart'; +import 'package:talker_http_logger/http_request_log.dart'; +import 'package:talker_http_logger/http_response_log.dart'; +import 'package:talker_http_logger/talker_http_logger_settings.dart'; + +class TalkerHttpLogger extends InterceptorContract { + TalkerHttpLogger({ + Talker? talker, + this.settings = const TalkerHttpLoggerSettings(), + }) { + _talker = talker ?? Talker(); + } + + late final Talker _talker; + + /// [TalkerHttpLogger] settings and customization + TalkerHttpLoggerSettings settings; + + @override + Future interceptRequest({ + required BaseRequest request, + }) async { + final message = '${request.url}'; + _talker.logCustom( + HttpRequestLog( + message, + request: request, + settings: settings, + ), + ); + return request; + } + + @override + Future interceptResponse({ + required BaseResponse response, + }) async { + final String message = '${response.request?.url}'; + + if (response.statusCode < 400) { + _talker.logCustom( + HttpResponseLog( + message, + response: response, + settings: settings, + ), + ); + } else { + _talker.logCustom( + HttpErrorLog( + message, + response: response, + settings: settings, + ), + ); + } + + return response; + } +} From a40681927241916851c7132c9fbcb195b830a1ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Sat, 3 May 2025 13:22:09 +0100 Subject: [PATCH 02/30] :construction: update SDK and dependency versions in pubspec.yaml --- packages/talker_http_logger/pubspec.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/talker_http_logger/pubspec.yaml b/packages/talker_http_logger/pubspec.yaml index 9e5ae4836..a8f6ffff5 100644 --- a/packages/talker_http_logger/pubspec.yaml +++ b/packages/talker_http_logger/pubspec.yaml @@ -4,12 +4,12 @@ version: 0.1.0-dev.43 homepage: https://github.com/Frezyx/talker environment: - sdk: ^3.0.3 + sdk: ^3.0.0 dependencies: http_interceptor: ^2.0.0 - talker: ^4.7.2 + talker: ^4.7.5 dev_dependencies: - lints: ^2.0.0 - test: ^1.21.0 + lints: ^5.1.1 + test: ^1.25.15 From d87e168c5576c3f1a276d9d3f779fe7ebb21ee8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Sat, 3 May 2025 13:37:11 +0100 Subject: [PATCH 03/30] :construction: add more settings --- .../lib/talker_http_logger_settings.dart | 179 +++++++++++++++++- packages/talker_http_logger/pubspec.yaml | 3 +- .../test/settings_test.dart | 156 +++++++++++++++ 3 files changed, 336 insertions(+), 2 deletions(-) create mode 100644 packages/talker_http_logger/test/settings_test.dart diff --git a/packages/talker_http_logger/lib/talker_http_logger_settings.dart b/packages/talker_http_logger/lib/talker_http_logger_settings.dart index 62c70382f..ee84e4ea4 100644 --- a/packages/talker_http_logger/lib/talker_http_logger_settings.dart +++ b/packages/talker_http_logger/lib/talker_http_logger_settings.dart @@ -1,9 +1,186 @@ -class TalkerHttpLoggerSettings { +import 'package:http_interceptor/http_interceptor.dart' + show BaseRequest, BaseResponse; +import 'package:talker/talker.dart'; +import 'package:equatable/equatable.dart'; +import 'package:talker/talker.dart' show AnsiPen, LogLevel; + +typedef RequestFilter = bool Function(BaseRequest request); +typedef ResponseFilter = bool Function(BaseResponse response); + +class TalkerHttpLoggerSettings with EquatableMixin { const TalkerHttpLoggerSettings({ + this.enabled = true, + this.logLevel = LogLevel.debug, + this.printResponseData = true, + this.printResponseHeaders = false, + this.printResponseMessage = true, + this.printResponseRedirects = false, + this.printResponseTime = false, + this.printErrorData = true, + this.printErrorHeaders = true, + this.printErrorMessage = true, + this.printRequestData = true, + this.printRequestHeaders = false, + this.printRequestCurl = false, this.hiddenHeaders = const {}, + this.requestPen, + this.responsePen, + this.errorPen, + this.requestFilter, + this.responseFilter, + this.errorFilter, }); + /// Print Chopper logger if true + final bool enabled; + + // LogLevel, default is debug + final LogLevel logLevel; + + /// Print [response.data] if true + final bool printResponseData; + + /// Print [response.headers] if true + final bool printResponseHeaders; + + /// Print [response.statusMessage] if true + final bool printResponseMessage; + + /// Print [response.redirects] if true + final bool printResponseRedirects; + + /// Print response time if true + final bool printResponseTime; + + /// Print [error.response.data] if true + final bool printErrorData; + + /// Print [error.response.headers] if true + final bool printErrorHeaders; + + /// Print [error.message] if true + final bool printErrorMessage; + + /// Print [request.data] if true + final bool printRequestData; + + /// Print [request.headers] if true + final bool printRequestHeaders; + + /// Prints a curl request equivalent of the network call if true + final bool printRequestCurl; + + /// Field to set custom http request console logs color + ///``` + ///// Red color + ///final redPen = AnsiPen()..red(); + /// + ///// Blue color + ///final redPen = AnsiPen()..blue(); + ///``` + /// More details in [AnsiPen] docs + final AnsiPen? requestPen; + + /// Field to set custom http response console logs color + ///``` + ///// Red color + ///final redPen = AnsiPen()..red(); + /// + ///// Blue color + ///final redPen = AnsiPen()..blue(); + ///``` + /// More details in [AnsiPen] docs + final AnsiPen? responsePen; + + /// Field to set custom http error console logs color + ///``` + ///// Red color + ///final redPen = AnsiPen()..red(); + /// + ///// Blue color + ///final redPen = AnsiPen()..blue(); + ///``` + /// More details in [AnsiPen] docs + final AnsiPen? errorPen; + + /// For request filtering. + /// You can add your custom logic to log only specific HTTP requests [Request]. + final RequestFilter? requestFilter; + + /// For response filtering. + /// You can add your custom logic to log only specific HTTP responses [Response]. + final ResponseFilter? responseFilter; + + /// For error filtering. + /// You can add your custom logic to log only specific Chopper error [Response]. + final ResponseFilter? errorFilter; + /// Header values for the specified keys in the Set will be replaced with *****. /// Case insensitive final Set hiddenHeaders; + + TalkerHttpLoggerSettings copyWith({ + bool? enabled, + LogLevel? logLevel, + bool? printResponseData, + bool? printResponseHeaders, + bool? printResponseMessage, + bool? printResponseTime, + bool? printErrorData, + bool? printErrorHeaders, + bool? printErrorMessage, + bool? printRequestData, + bool? printRequestHeaders, + bool? printRequestCurl, + AnsiPen? requestPen, + AnsiPen? responsePen, + AnsiPen? errorPen, + RequestFilter? requestFilter, + ResponseFilter? responseFilter, + ResponseFilter? errorFilter, + Set? hiddenHeaders, + }) => + TalkerHttpLoggerSettings( + enabled: enabled ?? this.enabled, + logLevel: logLevel ?? this.logLevel, + printResponseData: printResponseData ?? this.printResponseData, + printResponseHeaders: printResponseHeaders ?? this.printResponseHeaders, + printResponseMessage: printResponseMessage ?? this.printResponseMessage, + printResponseTime: printResponseTime ?? this.printResponseTime, + printErrorData: printErrorData ?? this.printErrorData, + printErrorHeaders: printErrorHeaders ?? this.printErrorHeaders, + printErrorMessage: printErrorMessage ?? this.printErrorMessage, + printRequestData: printRequestData ?? this.printRequestData, + printRequestHeaders: printRequestHeaders ?? this.printRequestHeaders, + printRequestCurl: printRequestCurl ?? this.printRequestCurl, + requestPen: requestPen ?? this.requestPen, + responsePen: responsePen ?? this.responsePen, + errorPen: errorPen ?? this.errorPen, + requestFilter: requestFilter ?? this.requestFilter, + responseFilter: responseFilter ?? this.responseFilter, + errorFilter: errorFilter ?? this.errorFilter, + hiddenHeaders: hiddenHeaders ?? this.hiddenHeaders, + ); + + @override + List get props => [ + enabled, + printResponseData, + printResponseHeaders, + printResponseMessage, + printResponseTime, + printErrorData, + printErrorHeaders, + printErrorMessage, + printRequestData, + printRequestHeaders, + printRequestCurl, + requestPen, + responsePen, + errorPen, + requestFilter, + responseFilter, + errorFilter, + hiddenHeaders, + ]; } diff --git a/packages/talker_http_logger/pubspec.yaml b/packages/talker_http_logger/pubspec.yaml index a8f6ffff5..9e84b7eaf 100644 --- a/packages/talker_http_logger/pubspec.yaml +++ b/packages/talker_http_logger/pubspec.yaml @@ -1,6 +1,6 @@ name: talker_http_logger description: Lightweight and customizable http client logger on talker base -version: 0.1.0-dev.43 +version: 1.0.0 homepage: https://github.com/Frezyx/talker environment: @@ -8,6 +8,7 @@ environment: dependencies: http_interceptor: ^2.0.0 + equatable: ^2.0.7 talker: ^4.7.5 dev_dependencies: diff --git a/packages/talker_http_logger/test/settings_test.dart b/packages/talker_http_logger/test/settings_test.dart new file mode 100644 index 000000000..503cf9b9e --- /dev/null +++ b/packages/talker_http_logger/test/settings_test.dart @@ -0,0 +1,156 @@ +import 'package:http_interceptor/http_interceptor.dart'; +import 'package:talker/talker.dart'; +import 'package:talker_http_logger/talker_http_logger.dart'; +import 'package:test/test.dart'; + +void main() { + group('TalkerHttpLoggerSettings', () { + late BaseRequest fakeRequest; + + setUp(() { + fakeRequest = Request(HttpMethod.GET.name, Uri.parse('/test')); + }); + + test('copyWith should create a new instance with the provided values', () { + final TalkerHttpLoggerSettings originalSettings = + const TalkerHttpLoggerSettings(); + final TalkerHttpLoggerSettings updatedSettings = + originalSettings.copyWith( + printResponseData: false, + printRequestHeaders: true, + printErrorHeaders: false, + requestPen: AnsiPen()..yellow(), + responseFilter: null, + ); + + expect( + originalSettings.printResponseData, + isNot(same(updatedSettings.printResponseData)), + ); + expect(updatedSettings.printResponseData, isFalse); + expect( + originalSettings.printRequestHeaders, + isNot(same(updatedSettings.printRequestHeaders)), + ); + expect(updatedSettings.printRequestHeaders, isTrue); + expect( + originalSettings.printErrorHeaders, + isNot(same(updatedSettings.printErrorHeaders)), + ); + expect(updatedSettings.printErrorHeaders, isFalse); + expect( + updatedSettings.requestPen, + isNot(same(originalSettings.requestPen)), + ); + expect(updatedSettings.responseFilter, isNull); + + expect(originalSettings, equals(originalSettings.copyWith())); + }); + + test('requestFilter should return true for allowed paths', () { + final TalkerHttpLoggerSettings settings = TalkerHttpLoggerSettings( + requestFilter: (BaseRequest request) => request.url.path == '/allowed', + ); + + final Request allowedRequestOptions = Request( + HttpMethod.GET.name, + Uri.parse('/allowed'), + ); + + final Request disallowedRequestOptions = Request( + HttpMethod.GET.name, + Uri.parse('/disallowed'), + ); + + expect(settings.requestFilter?.call(allowedRequestOptions), isTrue); + expect(settings.requestFilter?.call(disallowedRequestOptions), isFalse); + }); + + test('responseFilter should return true for successful responses', () { + final TalkerHttpLoggerSettings settings = TalkerHttpLoggerSettings( + responseFilter: (BaseResponse response) => + response.statusCode == 200); + + final Response successfulResponse = + Response('responseBodyBase', 200, request: fakeRequest); + + final Response unsuccessfulResponse = + Response('responseErrorBodyBase', 404, request: fakeRequest); + + expect(settings.responseFilter?.call(successfulResponse), isTrue); + expect(settings.responseFilter?.call(unsuccessfulResponse), isFalse); + }); + + test( + 'copyWith should create a new instance with updated values for all fields', + () { + final TalkerHttpLoggerSettings originalSettings = + TalkerHttpLoggerSettings( + printResponseData: true, + printResponseHeaders: false, + printResponseMessage: true, + printRequestData: true, + printRequestHeaders: false, + printErrorHeaders: false, + printErrorData: true, + requestPen: AnsiPen()..green(), + responsePen: AnsiPen()..cyan(), + errorPen: AnsiPen()..red(), + ); + + final TalkerHttpLoggerSettings updatedSettings = + originalSettings.copyWith( + printResponseData: false, + printRequestHeaders: true, + printErrorHeaders: true, + printErrorData: false, + requestPen: AnsiPen()..yellow(), + ); + + expect(updatedSettings.printResponseData, isFalse); + expect(updatedSettings.printResponseHeaders, isFalse); + expect(updatedSettings.printResponseMessage, isTrue); + expect(updatedSettings.printRequestData, isTrue); + expect(updatedSettings.printErrorHeaders, isTrue); + expect(updatedSettings.printErrorData, isFalse); + expect(updatedSettings.printRequestHeaders, isTrue); + expect( + updatedSettings.requestPen, + isNot(same(originalSettings.requestPen)), + ); + expect( + updatedSettings.responsePen, + equals(originalSettings.responsePen), + ); + expect( + updatedSettings.errorPen, + equals(originalSettings.errorPen), + ); + }, + ); + + test('default logLevel should be debug', () { + final TalkerHttpLoggerSettings settings = + const TalkerHttpLoggerSettings(); + expect(settings.logLevel, equals(LogLevel.debug)); + }); + + test('copyWith should preserve logLevel if not specified', () { + final TalkerHttpLoggerSettings originalSettings = + const TalkerHttpLoggerSettings(logLevel: LogLevel.warning); + final TalkerHttpLoggerSettings updatedSettings = + originalSettings.copyWith(printResponseData: false); + + expect(updatedSettings.logLevel, equals(LogLevel.warning)); + }); + + test('copyWith should update logLevel when specified', () { + final TalkerHttpLoggerSettings originalSettings = + const TalkerHttpLoggerSettings(logLevel: LogLevel.debug); + final TalkerHttpLoggerSettings updatedSettings = + originalSettings.copyWith(logLevel: LogLevel.error); + + expect(updatedSettings.logLevel, equals(LogLevel.error)); + }); + }); +} From 38b2f33bf1a835756940b43d5d55548c852c56a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Sat, 3 May 2025 13:58:43 +0100 Subject: [PATCH 04/30] :construction: add more settings --- .../lib/talker_http_logger_interceptor.dart | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart b/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart index 85dc28ba1..6bf0978a9 100644 --- a/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart +++ b/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart @@ -18,6 +18,50 @@ class TalkerHttpLogger extends InterceptorContract { /// [TalkerHttpLogger] settings and customization TalkerHttpLoggerSettings settings; + /// Method to update [settings] of [TalkerHttpLogger] + void configure({ + bool? enabled, + LogLevel? logLevel, + bool? printResponseData, + bool? printResponseHeaders, + bool? printResponseMessage, + bool? printResponseTime, + bool? printErrorData, + bool? printErrorHeaders, + bool? printErrorMessage, + bool? printRequestData, + bool? printRequestHeaders, + bool? printRequestCurl, + AnsiPen? requestPen, + AnsiPen? responsePen, + AnsiPen? errorPen, + RequestFilter? requestFilter, + ResponseFilter? responseFilter, + ResponseFilter? errorFilter, + Set? hiddenHeaders, + }) => + settings = settings.copyWith( + enabled: enabled, + logLevel: logLevel, + printRequestData: printRequestData, + printRequestHeaders: printRequestHeaders, + printRequestCurl: printRequestCurl, + printResponseData: printResponseData, + printErrorData: printErrorData, + printErrorHeaders: printErrorHeaders, + printErrorMessage: printErrorMessage, + printResponseHeaders: printResponseHeaders, + printResponseMessage: printResponseMessage, + requestPen: requestPen, + responsePen: responsePen, + errorPen: errorPen, + requestFilter: requestFilter, + responseFilter: responseFilter, + errorFilter: errorFilter, + hiddenHeaders: hiddenHeaders, + printResponseTime: printResponseTime, + ); + @override Future interceptRequest({ required BaseRequest request, From 8dc59430e0882a8133f2c48341bc7b99064f0ad6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Sat, 3 May 2025 14:01:02 +0100 Subject: [PATCH 05/30] :construction: wip --- .../lib/talker_http_logger_interceptor.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart b/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart index 6bf0978a9..a62cdd786 100644 --- a/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart +++ b/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart @@ -9,6 +9,7 @@ class TalkerHttpLogger extends InterceptorContract { TalkerHttpLogger({ Talker? talker, this.settings = const TalkerHttpLoggerSettings(), + this.addonId, }) { _talker = talker ?? Talker(); } @@ -18,6 +19,9 @@ class TalkerHttpLogger extends InterceptorContract { /// [TalkerHttpLogger] settings and customization TalkerHttpLoggerSettings settings; + /// Talker addon functionality addon id for creating a lot of addons + final String? addonId; + /// Method to update [settings] of [TalkerHttpLogger] void configure({ bool? enabled, From e0b30f96fdd2c4aa5e705087cad34416e47d030f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Sat, 3 May 2025 14:02:25 +0100 Subject: [PATCH 06/30] :construction: wip --- .../talker_http_logger/lib/talker_http_logger_interceptor.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart b/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart index a62cdd786..5f399db3c 100644 --- a/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart +++ b/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart @@ -70,10 +70,9 @@ class TalkerHttpLogger extends InterceptorContract { Future interceptRequest({ required BaseRequest request, }) async { - final message = '${request.url}'; _talker.logCustom( HttpRequestLog( - message, + request.url.toString(), request: request, settings: settings, ), From 8e7ed8b720433cb09afee405bfddff248723a39f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Sat, 3 May 2025 14:19:27 +0100 Subject: [PATCH 07/30] :construction: wip --- .../lib/http_error_log.dart | 4 +- .../lib/http_request_log.dart | 2 +- .../lib/http_response_log.dart | 2 +- .../lib/talker_http_logger_interceptor.dart | 75 ++++++++++++------- .../lib/talker_http_logger_settings.dart | 6 -- 5 files changed, 53 insertions(+), 36 deletions(-) diff --git a/packages/talker_http_logger/lib/http_error_log.dart b/packages/talker_http_logger/lib/http_error_log.dart index d04710493..6e0cc7bfb 100644 --- a/packages/talker_http_logger/lib/http_error_log.dart +++ b/packages/talker_http_logger/lib/http_error_log.dart @@ -8,7 +8,9 @@ class HttpErrorLog extends TalkerLog { HttpErrorLog( super.title, { required this.response, - this.settings = const TalkerHttpLoggerSettings(), + required this.settings, + super.exception, + super.stackTrace, }); final BaseResponse response; diff --git a/packages/talker_http_logger/lib/http_request_log.dart b/packages/talker_http_logger/lib/http_request_log.dart index 8d7974628..708ca7187 100644 --- a/packages/talker_http_logger/lib/http_request_log.dart +++ b/packages/talker_http_logger/lib/http_request_log.dart @@ -8,7 +8,7 @@ class HttpRequestLog extends TalkerLog { HttpRequestLog( super.title, { required this.request, - this.settings = const TalkerHttpLoggerSettings(), + required this.settings, }); final BaseRequest request; diff --git a/packages/talker_http_logger/lib/http_response_log.dart b/packages/talker_http_logger/lib/http_response_log.dart index 84ad92a5c..1bdaa65ba 100644 --- a/packages/talker_http_logger/lib/http_response_log.dart +++ b/packages/talker_http_logger/lib/http_response_log.dart @@ -8,7 +8,7 @@ class HttpResponseLog extends TalkerLog { HttpResponseLog( super.title, { required this.response, - this.settings = const TalkerHttpLoggerSettings(), + required this.settings, }); final BaseResponse response; diff --git a/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart b/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart index 5f399db3c..ce2fe7f15 100644 --- a/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart +++ b/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart @@ -29,7 +29,6 @@ class TalkerHttpLogger extends InterceptorContract { bool? printResponseData, bool? printResponseHeaders, bool? printResponseMessage, - bool? printResponseTime, bool? printErrorData, bool? printErrorHeaders, bool? printErrorMessage, @@ -63,20 +62,22 @@ class TalkerHttpLogger extends InterceptorContract { responseFilter: responseFilter, errorFilter: errorFilter, hiddenHeaders: hiddenHeaders, - printResponseTime: printResponseTime, ); @override Future interceptRequest({ required BaseRequest request, }) async { - _talker.logCustom( - HttpRequestLog( - request.url.toString(), - request: request, - settings: settings, - ), - ); + if (settings.enabled && (settings.requestFilter?.call(request) ?? true)) { + _talker.logCustom( + HttpRequestLog( + request.url.toString(), + request: request, + settings: settings, + ), + ); + } + return request; } @@ -86,24 +87,44 @@ class TalkerHttpLogger extends InterceptorContract { }) async { final String message = '${response.request?.url}'; - if (response.statusCode < 400) { - _talker.logCustom( - HttpResponseLog( - message, - response: response, - settings: settings, - ), - ); - } else { - _talker.logCustom( - HttpErrorLog( - message, - response: response, - settings: settings, - ), - ); - } + try { + switch (response.statusCode) { + case int statusCode when settings.enabled && statusCode < 400: + if (settings.responseFilter?.call(response) ?? true) { + _talker.logCustom( + HttpResponseLog( + message, + response: response, + settings: settings, + ), + ); + } + break; + case _ when settings.enabled: + if (settings.errorFilter?.call(response) ?? true) { + _talker.logCustom( + HttpErrorLog( + message, + response: response, + settings: settings, + ), + ); + } + break; + } - return response; + return response; + } catch (exception, stackTrace) { + switch (exception) { + case ClientException ex when settings.enabled: + _talker.error(ex.uri.toString(), ex, stackTrace); + break; + case _ when settings.enabled: + _talker.error(exception.toString(), exception, stackTrace); + break; + } + + rethrow; + } } } diff --git a/packages/talker_http_logger/lib/talker_http_logger_settings.dart b/packages/talker_http_logger/lib/talker_http_logger_settings.dart index ee84e4ea4..3e8b57a79 100644 --- a/packages/talker_http_logger/lib/talker_http_logger_settings.dart +++ b/packages/talker_http_logger/lib/talker_http_logger_settings.dart @@ -15,7 +15,6 @@ class TalkerHttpLoggerSettings with EquatableMixin { this.printResponseHeaders = false, this.printResponseMessage = true, this.printResponseRedirects = false, - this.printResponseTime = false, this.printErrorData = true, this.printErrorHeaders = true, this.printErrorMessage = true, @@ -49,9 +48,6 @@ class TalkerHttpLoggerSettings with EquatableMixin { /// Print [response.redirects] if true final bool printResponseRedirects; - /// Print response time if true - final bool printResponseTime; - /// Print [error.response.data] if true final bool printErrorData; @@ -146,7 +142,6 @@ class TalkerHttpLoggerSettings with EquatableMixin { printResponseData: printResponseData ?? this.printResponseData, printResponseHeaders: printResponseHeaders ?? this.printResponseHeaders, printResponseMessage: printResponseMessage ?? this.printResponseMessage, - printResponseTime: printResponseTime ?? this.printResponseTime, printErrorData: printErrorData ?? this.printErrorData, printErrorHeaders: printErrorHeaders ?? this.printErrorHeaders, printErrorMessage: printErrorMessage ?? this.printErrorMessage, @@ -168,7 +163,6 @@ class TalkerHttpLoggerSettings with EquatableMixin { printResponseData, printResponseHeaders, printResponseMessage, - printResponseTime, printErrorData, printErrorHeaders, printErrorMessage, From 6e3a263f8978d53472c3d19793162abb0b0efe11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Sat, 3 May 2025 14:22:20 +0100 Subject: [PATCH 08/30] :construction: wip --- packages/talker_http_logger/lib/http_error_log.dart | 9 ++++++++- packages/talker_http_logger/lib/http_request_log.dart | 9 ++++++++- packages/talker_http_logger/lib/http_response_log.dart | 9 ++++++++- packages/talker_http_logger/pubspec.yaml | 3 ++- 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/packages/talker_http_logger/lib/http_error_log.dart b/packages/talker_http_logger/lib/http_error_log.dart index 6e0cc7bfb..998616575 100644 --- a/packages/talker_http_logger/lib/http_error_log.dart +++ b/packages/talker_http_logger/lib/http_error_log.dart @@ -1,6 +1,7 @@ import 'dart:convert' show JsonEncoder; import 'package:http_interceptor/http_interceptor.dart'; +import 'package:meta/meta.dart'; import 'package:talker/talker.dart'; import 'package:talker_http_logger/talker_http_logger_settings.dart'; @@ -24,6 +25,12 @@ class HttpErrorLog extends TalkerLog { @override String get key => TalkerLogType.httpError.key; + @override + LogLevel get logLevel => LogLevel.error; + + @visibleForTesting + String convert(Object? object) => _encoder.convert(object); + @override String generateTextMessage({ TimeFormat timeFormat = TimeFormat.timeAndSeconds, @@ -37,7 +44,7 @@ class HttpErrorLog extends TalkerLog { try { if (response.request?.headers.isNotEmpty ?? false) { - msg.write('Headers: ${_encoder.convert(response.request?.headers)}'); + msg.write('Headers: ${convert(response.request?.headers)}'); } } catch (_) { // TODO: add handling can`t convert diff --git a/packages/talker_http_logger/lib/http_request_log.dart b/packages/talker_http_logger/lib/http_request_log.dart index 708ca7187..8588d9e47 100644 --- a/packages/talker_http_logger/lib/http_request_log.dart +++ b/packages/talker_http_logger/lib/http_request_log.dart @@ -1,6 +1,7 @@ import 'dart:convert' show JsonEncoder; import 'package:http_interceptor/http_interceptor.dart'; +import 'package:meta/meta.dart'; import 'package:talker/talker.dart'; import 'package:talker_http_logger/talker_http_logger_settings.dart'; @@ -23,6 +24,12 @@ class HttpRequestLog extends TalkerLog { @override String get key => TalkerLogType.httpRequest.key; + @override + LogLevel get logLevel => settings.logLevel; + + @visibleForTesting + String convert(Object? object) => _encoder.convert(object); + @override String generateTextMessage({ TimeFormat timeFormat = TimeFormat.timeAndSeconds, @@ -45,7 +52,7 @@ class HttpRequestLog extends TalkerLog { : value; }); } - msg.write('Headers: ${_encoder.convert(headers)}'); + msg.write('Headers: ${convert(headers)}'); } } catch (_) { // TODO: add handling can`t convert diff --git a/packages/talker_http_logger/lib/http_response_log.dart b/packages/talker_http_logger/lib/http_response_log.dart index 1bdaa65ba..b2e3f3511 100644 --- a/packages/talker_http_logger/lib/http_response_log.dart +++ b/packages/talker_http_logger/lib/http_response_log.dart @@ -1,6 +1,7 @@ import 'dart:convert' show JsonEncoder; import 'package:http_interceptor/http_interceptor.dart'; +import 'package:meta/meta.dart'; import 'package:talker/talker.dart'; import 'package:talker_http_logger/talker_http_logger_settings.dart'; @@ -22,6 +23,12 @@ class HttpResponseLog extends TalkerLog { @override String get key => TalkerLogType.httpResponse.key; + @override + LogLevel get logLevel => settings.logLevel; + + @visibleForTesting + String convert(Object? object) => _encoder.convert(object); + @override String generateTextMessage({ TimeFormat timeFormat = TimeFormat.timeAndSeconds, @@ -35,7 +42,7 @@ class HttpResponseLog extends TalkerLog { try { if (response.request?.headers.isNotEmpty ?? false) { - msg.write('Headers: ${_encoder.convert(response.request?.headers)}'); + msg.write('Headers: ${convert(response.request?.headers)}'); } } catch (_) { // TODO: add handling can`t convert diff --git a/packages/talker_http_logger/pubspec.yaml b/packages/talker_http_logger/pubspec.yaml index 9e84b7eaf..466bc32cc 100644 --- a/packages/talker_http_logger/pubspec.yaml +++ b/packages/talker_http_logger/pubspec.yaml @@ -7,8 +7,9 @@ environment: sdk: ^3.0.0 dependencies: - http_interceptor: ^2.0.0 equatable: ^2.0.7 + http_interceptor: ^2.0.0 + meta: ^1.9.1 talker: ^4.7.5 dev_dependencies: From 7a4185baa119043fc7e2a692487b3034516d7e70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Sat, 3 May 2025 16:58:24 +0100 Subject: [PATCH 09/30] :construction: wip --- .../talker_http_logger/lib/curl_request.dart | 43 +++++++++++++++++++ .../lib/http_error_log.dart | 2 +- .../lib/http_request_log.dart | 2 +- .../lib/http_response_log.dart | 2 +- .../lib/talker_http_logger_interceptor.dart | 2 + .../lib/talker_http_logger_settings.dart | 6 +++ .../test/talker_http_logger_test.dart | 1 - 7 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 packages/talker_http_logger/lib/curl_request.dart delete mode 100644 packages/talker_http_logger/test/talker_http_logger_test.dart diff --git a/packages/talker_http_logger/lib/curl_request.dart b/packages/talker_http_logger/lib/curl_request.dart new file mode 100644 index 000000000..8f9179194 --- /dev/null +++ b/packages/talker_http_logger/lib/curl_request.dart @@ -0,0 +1,43 @@ +import 'dart:convert' show JsonEncoder, jsonDecode; + +import 'package:http_interceptor/http_interceptor.dart'; + +const JsonEncoder _encoder = JsonEncoder(); + +extension CurlRequest on BaseRequest { + /// Converts the request to a curl command string. + String toCurl({Map? headers}) { + final List curl = ['curl', '-v', '-X', method]; + + curl.addAll((headers ?? this.headers) + .entries + .map((e) => "-H ${_q('${e.key}: ${e.value}')}")); + + switch (this) { + case Request req when req.body.isNotEmpty: + try { + curl.addAll(['-d', _q(_encoder.convert(jsonDecode(req.body)))]); + } on FormatException { + curl.addAll(['-d', _q(req.body)]); + } + break; + case MultipartRequest req: + for (final MapEntry field in req.fields.entries) { + curl.addAll(['-F', _q('${field.key}=${field.value}')]); + } + for (final MultipartFile file in req.files) { + curl.addAll(['-F', _q('${file.field}=@${file.filename}')]); + } + break; + default: + break; + } + + curl.add(_q(url.toString())); + + return curl.join(' '); + } + + /// single-quoting with sane escaping of `'` + String _q(String s) => "'${s.replaceAll("'", r"'\''")}'"; +} diff --git a/packages/talker_http_logger/lib/http_error_log.dart b/packages/talker_http_logger/lib/http_error_log.dart index 998616575..27db2b46c 100644 --- a/packages/talker_http_logger/lib/http_error_log.dart +++ b/packages/talker_http_logger/lib/http_error_log.dart @@ -20,7 +20,7 @@ class HttpErrorLog extends TalkerLog { static const JsonEncoder _encoder = JsonEncoder.withIndent(' '); @override - AnsiPen get pen => AnsiPen()..red(); + AnsiPen get pen => settings.errorPen ?? (AnsiPen()..red()); @override String get key => TalkerLogType.httpError.key; diff --git a/packages/talker_http_logger/lib/http_request_log.dart b/packages/talker_http_logger/lib/http_request_log.dart index 8588d9e47..55faea74c 100644 --- a/packages/talker_http_logger/lib/http_request_log.dart +++ b/packages/talker_http_logger/lib/http_request_log.dart @@ -19,7 +19,7 @@ class HttpRequestLog extends TalkerLog { static const String _hiddenValue = '*****'; @override - AnsiPen get pen => (AnsiPen()..xterm(219)); + AnsiPen get pen => settings.requestPen ?? (AnsiPen()..xterm(219)); @override String get key => TalkerLogType.httpRequest.key; diff --git a/packages/talker_http_logger/lib/http_response_log.dart b/packages/talker_http_logger/lib/http_response_log.dart index b2e3f3511..d0453612a 100644 --- a/packages/talker_http_logger/lib/http_response_log.dart +++ b/packages/talker_http_logger/lib/http_response_log.dart @@ -18,7 +18,7 @@ class HttpResponseLog extends TalkerLog { static const JsonEncoder _encoder = JsonEncoder.withIndent(' '); @override - AnsiPen get pen => (AnsiPen()..xterm(46)); + AnsiPen get pen => settings.responsePen ?? (AnsiPen()..xterm(46)); @override String get key => TalkerLogType.httpResponse.key; diff --git a/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart b/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart index ce2fe7f15..613b72d1b 100644 --- a/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart +++ b/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart @@ -29,6 +29,7 @@ class TalkerHttpLogger extends InterceptorContract { bool? printResponseData, bool? printResponseHeaders, bool? printResponseMessage, + bool? printResponseTime, bool? printErrorData, bool? printErrorHeaders, bool? printErrorMessage, @@ -62,6 +63,7 @@ class TalkerHttpLogger extends InterceptorContract { responseFilter: responseFilter, errorFilter: errorFilter, hiddenHeaders: hiddenHeaders, + printResponseTime: printResponseTime, ); @override diff --git a/packages/talker_http_logger/lib/talker_http_logger_settings.dart b/packages/talker_http_logger/lib/talker_http_logger_settings.dart index 3e8b57a79..ee84e4ea4 100644 --- a/packages/talker_http_logger/lib/talker_http_logger_settings.dart +++ b/packages/talker_http_logger/lib/talker_http_logger_settings.dart @@ -15,6 +15,7 @@ class TalkerHttpLoggerSettings with EquatableMixin { this.printResponseHeaders = false, this.printResponseMessage = true, this.printResponseRedirects = false, + this.printResponseTime = false, this.printErrorData = true, this.printErrorHeaders = true, this.printErrorMessage = true, @@ -48,6 +49,9 @@ class TalkerHttpLoggerSettings with EquatableMixin { /// Print [response.redirects] if true final bool printResponseRedirects; + /// Print response time if true + final bool printResponseTime; + /// Print [error.response.data] if true final bool printErrorData; @@ -142,6 +146,7 @@ class TalkerHttpLoggerSettings with EquatableMixin { printResponseData: printResponseData ?? this.printResponseData, printResponseHeaders: printResponseHeaders ?? this.printResponseHeaders, printResponseMessage: printResponseMessage ?? this.printResponseMessage, + printResponseTime: printResponseTime ?? this.printResponseTime, printErrorData: printErrorData ?? this.printErrorData, printErrorHeaders: printErrorHeaders ?? this.printErrorHeaders, printErrorMessage: printErrorMessage ?? this.printErrorMessage, @@ -163,6 +168,7 @@ class TalkerHttpLoggerSettings with EquatableMixin { printResponseData, printResponseHeaders, printResponseMessage, + printResponseTime, printErrorData, printErrorHeaders, printErrorMessage, diff --git a/packages/talker_http_logger/test/talker_http_logger_test.dart b/packages/talker_http_logger/test/talker_http_logger_test.dart deleted file mode 100644 index 8b1378917..000000000 --- a/packages/talker_http_logger/test/talker_http_logger_test.dart +++ /dev/null @@ -1 +0,0 @@ - From 7c869ff66661b13f743f2e37c1e8958ebed332ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Sat, 3 May 2025 17:00:48 +0100 Subject: [PATCH 10/30] :construction: wip --- .../lib/http_request_log.dart | 84 +++++++++++++++---- 1 file changed, 69 insertions(+), 15 deletions(-) diff --git a/packages/talker_http_logger/lib/http_request_log.dart b/packages/talker_http_logger/lib/http_request_log.dart index 55faea74c..b425e1f88 100644 --- a/packages/talker_http_logger/lib/http_request_log.dart +++ b/packages/talker_http_logger/lib/http_request_log.dart @@ -1,8 +1,9 @@ -import 'dart:convert' show JsonEncoder; +import 'dart:convert' show JsonEncoder, jsonDecode; import 'package:http_interceptor/http_interceptor.dart'; import 'package:meta/meta.dart'; import 'package:talker/talker.dart'; +import 'package:talker_http_logger/curl_request.dart'; import 'package:talker_http_logger/talker_http_logger_settings.dart'; class HttpRequestLog extends TalkerLog { @@ -41,23 +42,76 @@ class HttpRequestLog extends TalkerLog { final Map headers = {...request.headers}; - try { - if (headers.isNotEmpty) { - if (settings.hiddenHeaders.isNotEmpty) { - headers.updateAll((String key, String value) { - return settings.hiddenHeaders - .map((v) => v.toLowerCase()) - .contains(key.toLowerCase()) - ? _hiddenValue - : value; - }); - } - msg.write('Headers: ${convert(headers)}'); + // HTTP headers are case-insensitive by standard + _replaceHiddenHeaders(headers); + + if (settings.printRequestCurl) { + msg.writeln('[cURL] ${request.toCurl(headers: headers)}'); + } + + if (settings.printRequestHeaders && headers.isNotEmpty) { + try { + msg.writeln('Headers: ${convert(headers)}'); + } catch (error, stackTrace) { + msg.writeln( + 'Headers: ', + ); + } + } + + if (settings.printRequestData) { + switch (request) { + case Request req when req.body.isNotEmpty: + late final dynamic jsonData; + try { + jsonData = jsonDecode(req.body); + } catch (_) { + jsonData = null; + } + + try { + if (jsonData != null) { + msg.writeln('Data: ${convert(jsonData)}'); + break; + } else { + msg.writeln('Data: ${req.body}'); + break; + } + } catch (error, stackTrace) { + msg.writeln( + 'Data: ', + ); + } + break; + case MultipartRequest req + when req.fields.isNotEmpty || req.files.isNotEmpty: + msg.writeln('Data: ${convert( + { + ...req.fields, + for (final MultipartFile file in req.files) + file.field: file.filename ?? '' + }, + )}'); + break; + default: + break; } - } catch (_) { - // TODO: add handling can`t convert } return msg.toString().trimRight(); } + + void _replaceHiddenHeaders(Map headers) { + if (settings.hiddenHeaders.isEmpty || headers.isEmpty) { + return; + } + + // HTTP headers are case-insensitive by standard + final Set hiddenLower = settings.hiddenHeaders + .map((String header) => header.toLowerCase()) + .toSet(); + + headers.updateAll((String k, String v) => + hiddenLower.contains(k.toLowerCase()) ? _hiddenValue : v); + } } From fbdef9748b0fd9ee2ae737abe14278073f20a2f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Sat, 3 May 2025 21:06:53 +0100 Subject: [PATCH 11/30] :speech_balloon: update workflow name for consistency --- .../lib/http_error_log.dart | 34 +++++++++++++----- .../lib/http_response_log.dart | 35 ++++++++++++++++--- .../lib/talker_http_logger_interceptor.dart | 1 + 3 files changed, 56 insertions(+), 14 deletions(-) diff --git a/packages/talker_http_logger/lib/http_error_log.dart b/packages/talker_http_logger/lib/http_error_log.dart index 27db2b46c..d7b756efb 100644 --- a/packages/talker_http_logger/lib/http_error_log.dart +++ b/packages/talker_http_logger/lib/http_error_log.dart @@ -8,12 +8,14 @@ import 'package:talker_http_logger/talker_http_logger_settings.dart'; class HttpErrorLog extends TalkerLog { HttpErrorLog( super.title, { + this.request, required this.response, required this.settings, super.exception, super.stackTrace, }); + final BaseRequest? request; final BaseResponse response; final TalkerHttpLoggerSettings settings; @@ -36,18 +38,32 @@ class HttpErrorLog extends TalkerLog { TimeFormat timeFormat = TimeFormat.timeAndSeconds, }) { final StringBuffer msg = StringBuffer(); - msg.write('[$title]'); - msg.write(' [${response.request?.method}]'); - msg.writeln(' $message'); + msg.write('[$title]'); + msg.writeln(' [${response.request?.method ?? request?.method}]'); msg.writeln('Status: ${response.statusCode}'); - try { - if (response.request?.headers.isNotEmpty ?? false) { - msg.write('Headers: ${convert(response.request?.headers)}'); - } - } catch (_) { - // TODO: add handling can`t convert + final String? responseMessage = switch (exception) { + ClientException ex => ex.message, + Exception ex => ex.toString(), + _ => message, + }; + + if (settings.printErrorMessage && (responseMessage?.isNotEmpty ?? false)) { + msg.writeln('Message: $responseMessage'); + } + + if (settings.printErrorHeaders && response.headers.isNotEmpty) { + msg.writeln('Headers: ${convert(response.headers)}'); + } + + final String? data = switch (response) { + Response res => res.body, + _ => null, + }; + + if (settings.printErrorData && data != null) { + msg.writeln('Data: $data}'); } return msg.toString().trimRight(); diff --git a/packages/talker_http_logger/lib/http_response_log.dart b/packages/talker_http_logger/lib/http_response_log.dart index d0453612a..bfdce89b7 100644 --- a/packages/talker_http_logger/lib/http_response_log.dart +++ b/packages/talker_http_logger/lib/http_response_log.dart @@ -38,14 +38,39 @@ class HttpResponseLog extends TalkerLog { msg.write(' [${response.request?.method}]'); msg.write(' $message'); + final String? data = switch (response) { + Response res => res.body, + _ => null, + }; + msg.writeln('Status: ${response.statusCode}'); - try { - if (response.request?.headers.isNotEmpty ?? false) { - msg.write('Headers: ${convert(response.request?.headers)}'); + if (settings.printResponseMessage && response.reasonPhrase != null) { + msg.writeln('Message: ${response.reasonPhrase}'); + } + + if (settings.printResponseHeaders && response.headers.isNotEmpty) { + try { + msg.writeln('Headers: ${convert(response.headers)}'); + } catch (error, stackTrace) { + msg.writeln( + 'Headers: ', + ); + } + } + + if (settings.printResponseRedirects && response.isRedirect) { + msg.writeln('Redirect: ${response.isRedirect}'); + } + + if (settings.printResponseData && data != null) { + try { + msg.writeln('Data: ${convert(data)}'); + } catch (error, stackTrace) { + msg.writeln( + 'Data: ', + ); } - } catch (_) { - // TODO: add handling can`t convert } return msg.toString().trimRight(); diff --git a/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart b/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart index 613b72d1b..4568a67d9 100644 --- a/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart +++ b/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart @@ -107,6 +107,7 @@ class TalkerHttpLogger extends InterceptorContract { _talker.logCustom( HttpErrorLog( message, + request: response.request, response: response, settings: settings, ), From 70e177a69b973ef632b44addb1689d5254772395 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Sat, 3 May 2025 22:23:30 +0100 Subject: [PATCH 12/30] :construction: wip --- .github/workflows/talker_http_logger.yaml | 20 +++++++++++++++++++ .../lib/http_error_log.dart | 11 +++++++++- .../lib/http_response_log.dart | 11 +++++++++- .../talker_http_logger/lib/response_time.dart | 15 ++++++++++++++ .../lib/talker_http_logger_interceptor.dart | 9 ++++++++- 5 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/talker_http_logger.yaml create mode 100644 packages/talker_http_logger/lib/response_time.dart diff --git a/.github/workflows/talker_http_logger.yaml b/.github/workflows/talker_http_logger.yaml new file mode 100644 index 000000000..1f70f20ea --- /dev/null +++ b/.github/workflows/talker_http_logger.yaml @@ -0,0 +1,20 @@ +name: talker_http_logger + +on: + push: + paths: + - "packages/talker_http_logger/**" + - ".github/workflows/talker_http_logger.yaml" + pull_request: + paths: + - "packages/talker_http_logger/**" + - ".github/workflows/talker_http_logger.yaml" +permissions: + contents: read + +jobs: + test: + uses: ./.github/workflows/test.yaml + with: + package: talker_http_logger + sdk: dart diff --git a/packages/talker_http_logger/lib/http_error_log.dart b/packages/talker_http_logger/lib/http_error_log.dart index d7b756efb..558d4e90b 100644 --- a/packages/talker_http_logger/lib/http_error_log.dart +++ b/packages/talker_http_logger/lib/http_error_log.dart @@ -3,9 +3,10 @@ import 'dart:convert' show JsonEncoder; import 'package:http_interceptor/http_interceptor.dart'; import 'package:meta/meta.dart'; import 'package:talker/talker.dart'; +import 'package:talker_http_logger/response_time.dart'; import 'package:talker_http_logger/talker_http_logger_settings.dart'; -class HttpErrorLog extends TalkerLog { +class HttpErrorLog extends TalkerLog with ResponseTime { HttpErrorLog( super.title, { this.request, @@ -49,6 +50,14 @@ class HttpErrorLog extends TalkerLog { _ => message, }; + if (settings.printResponseTime) { + final int? responseTime = getResponseTime(response.headers); + + if (responseTime != null) { + msg.writeln('Time: $responseTime ms'); + } + } + if (settings.printErrorMessage && (responseMessage?.isNotEmpty ?? false)) { msg.writeln('Message: $responseMessage'); } diff --git a/packages/talker_http_logger/lib/http_response_log.dart b/packages/talker_http_logger/lib/http_response_log.dart index bfdce89b7..9d19cad66 100644 --- a/packages/talker_http_logger/lib/http_response_log.dart +++ b/packages/talker_http_logger/lib/http_response_log.dart @@ -4,8 +4,9 @@ import 'package:http_interceptor/http_interceptor.dart'; import 'package:meta/meta.dart'; import 'package:talker/talker.dart'; import 'package:talker_http_logger/talker_http_logger_settings.dart'; +import 'package:talker_http_logger/response_time.dart'; -class HttpResponseLog extends TalkerLog { +class HttpResponseLog extends TalkerLog with ResponseTime { HttpResponseLog( super.title, { required this.response, @@ -45,6 +46,14 @@ class HttpResponseLog extends TalkerLog { msg.writeln('Status: ${response.statusCode}'); + if (settings.printResponseTime) { + final int? responseTime = getResponseTime(response.headers); + + if (responseTime != null) { + msg.writeln('Time: $responseTime ms'); + } + } + if (settings.printResponseMessage && response.reasonPhrase != null) { msg.writeln('Message: ${response.reasonPhrase}'); } diff --git a/packages/talker_http_logger/lib/response_time.dart b/packages/talker_http_logger/lib/response_time.dart new file mode 100644 index 000000000..01f8b5ac7 --- /dev/null +++ b/packages/talker_http_logger/lib/response_time.dart @@ -0,0 +1,15 @@ +import 'package:talker/talker.dart'; +import 'package:talker_http_logger/talker_http_logger_interceptor.dart'; + +mixin ResponseTime on TalkerLog { + int? getResponseTime(Map headers) { + final int? triggerTime = + int.tryParse(headers[TalkerHttpLogger.kLogsTimeStamp] ?? ''); + + if (triggerTime != null && triggerTime > 0) { + return DateTime.timestamp().millisecondsSinceEpoch - triggerTime; + } + + return null; + } +} diff --git a/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart b/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart index 4568a67d9..7548038bf 100644 --- a/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart +++ b/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart @@ -14,6 +14,8 @@ class TalkerHttpLogger extends InterceptorContract { _talker = talker ?? Talker(); } + static const String kLogsTimeStamp = '_talker_http_logger_ts_'; + late final Talker _talker; /// [TalkerHttpLogger] settings and customization @@ -74,7 +76,12 @@ class TalkerHttpLogger extends InterceptorContract { _talker.logCustom( HttpRequestLog( request.url.toString(), - request: request, + request: switch (settings.printResponseTime) { + true => request + ..headers[kLogsTimeStamp] = + DateTime.timestamp().millisecondsSinceEpoch.toString(), + false => request + }, settings: settings, ), ); From cb5615e39cb7c4ef77a303da825ba7ae2a7b4843 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Sun, 4 May 2025 21:26:23 +0100 Subject: [PATCH 13/30] :construction: wip --- packages/talker_http_logger/Makefile | 61 ++ .../lib/http_error_log.dart | 39 +- .../lib/http_response_log.dart | 11 +- .../talker_http_logger/lib/response_time.dart | 4 +- .../talker_http_logger/test/logger_test.dart | 368 +++++++++ .../talker_http_logger/test/logs_test.dart | 748 ++++++++++++++++++ .../tool/makefile_helpers.sh | 27 + 7 files changed, 1241 insertions(+), 17 deletions(-) create mode 100644 packages/talker_http_logger/Makefile create mode 100644 packages/talker_http_logger/test/logger_test.dart create mode 100644 packages/talker_http_logger/test/logs_test.dart create mode 100644 packages/talker_http_logger/tool/makefile_helpers.sh diff --git a/packages/talker_http_logger/Makefile b/packages/talker_http_logger/Makefile new file mode 100644 index 000000000..88be5adf5 --- /dev/null +++ b/packages/talker_http_logger/Makefile @@ -0,0 +1,61 @@ +# Makefile + +help: + @printf "%-20s %s\n" "Target" "Description" + @printf "%-20s %s\n" "------" "-----------" + @make -pqR : 2>/dev/null \ + | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' \ + | sort \ + | egrep -v -e '^[^[:alnum:]]' -e '^$@$$' \ + | xargs -I _ sh -c 'printf "%-20s " _; make _ -nB | (grep -i "^# Help:" || echo "") | tail -1 | sed "s/^# Help: //g"' + +analyze: + @# Help: Analyze the project's Dart code. + dart analyze --fatal-infos + +check_format: + @# Help: Check the formatting of one or more Dart files. + dart format --output=none --set-exit-if-changed . + +check_outdated: + @# Help: Check which of the project's packages are outdated. + dart pub outdated + +check_style: + @# Help: Analyze the project's Dart code and check the formatting one or more Dart files. + make analyze && make check_format + +code_gen: + @# Help: Run the build system for Dart code generation and modular compilation. + dart run build_runner build --delete-conflicting-outputs + +code_gen_watcher: + @# Help: Run the build system for Dart code generation and modular compilation as a watcher. + dart run build_runner watch --delete-conflicting-outputs + +format: + @# Help: Format one or more Dart files. + dart format . + +install: + @# Help: Install all the project's packages + dart pub get + +sure: + @# Help: Analyze the project's Dart code, check the formatting one or more Dart files and run unit tests for the current project. + make check_style && make tests + +show_test_coverage: + @# Help: Run Dart unit tests for the current project and show the coverage. + dart pub global activate coverage && dart pub global run coverage:test_with_coverage + lcov --remove coverage/lcov.info '**.g.dart' '**.mock.dart' '**.chopper.dart' -o coverage/lcov_without_generated_code.info --ignore-errors unused + genhtml coverage/lcov_without_generated_code.info -o coverage/html + source tool/makefile_helpers.sh && open_link "coverage/html/index.html" + +tests: + @# Help: Run Dart unit and widget tests for the current project. + dart test + +upgrade: + @# Help: Upgrade all the project's packages. + dart pub upgrade diff --git a/packages/talker_http_logger/lib/http_error_log.dart b/packages/talker_http_logger/lib/http_error_log.dart index 558d4e90b..4989c85c1 100644 --- a/packages/talker_http_logger/lib/http_error_log.dart +++ b/packages/talker_http_logger/lib/http_error_log.dart @@ -1,4 +1,4 @@ -import 'dart:convert' show JsonEncoder; +import 'dart:convert' show JsonEncoder, jsonDecode; import 'package:http_interceptor/http_interceptor.dart'; import 'package:meta/meta.dart'; @@ -10,14 +10,14 @@ class HttpErrorLog extends TalkerLog with ResponseTime { HttpErrorLog( super.title, { this.request, - required this.response, + this.response, required this.settings, super.exception, super.stackTrace, }); final BaseRequest? request; - final BaseResponse response; + final BaseResponse? response; final TalkerHttpLoggerSettings settings; static const JsonEncoder _encoder = JsonEncoder.withIndent(' '); @@ -41,17 +41,28 @@ class HttpErrorLog extends TalkerLog with ResponseTime { final StringBuffer msg = StringBuffer(); msg.write('[$title]'); - msg.writeln(' [${response.request?.method ?? request?.method}]'); - msg.writeln('Status: ${response.statusCode}'); + if (response?.request?.method != null || request?.method != null) { + msg.write(' [${response?.request?.method ?? request?.method}]'); + } + if (response?.request != null || request != null) { + msg.writeln(' ${response?.request?.url ?? request?.url}'); + } else { + msg.writeln(); + } + + if (response?.statusCode != null) { + msg.writeln('Status: ${response?.statusCode}'); + } final String? responseMessage = switch (exception) { ClientException ex => ex.message, Exception ex => ex.toString(), - _ => message, + _ => null, }; if (settings.printResponseTime) { - final int? responseTime = getResponseTime(response.headers); + final int? responseTime = getResponseTime(response?.headers) ?? + getResponseTime(response?.request?.headers); if (responseTime != null) { msg.writeln('Time: $responseTime ms'); @@ -62,8 +73,8 @@ class HttpErrorLog extends TalkerLog with ResponseTime { msg.writeln('Message: $responseMessage'); } - if (settings.printErrorHeaders && response.headers.isNotEmpty) { - msg.writeln('Headers: ${convert(response.headers)}'); + if (settings.printErrorHeaders && (response?.headers.isNotEmpty ?? false)) { + msg.writeln('Headers: ${convert(response?.headers)}'); } final String? data = switch (response) { @@ -71,8 +82,14 @@ class HttpErrorLog extends TalkerLog with ResponseTime { _ => null, }; - if (settings.printErrorData && data != null) { - msg.writeln('Data: $data}'); + if (settings.printErrorData && (data?.isNotEmpty ?? false)) { + try { + msg.writeln('Data: ${convert(jsonDecode(data!))}'); + } on FormatException { + msg.writeln('Data: ${convert(data)}'); + } catch (_) { + msg.writeln('Data: $data'); + } } return msg.toString().trimRight(); diff --git a/packages/talker_http_logger/lib/http_response_log.dart b/packages/talker_http_logger/lib/http_response_log.dart index 9d19cad66..9789905a1 100644 --- a/packages/talker_http_logger/lib/http_response_log.dart +++ b/packages/talker_http_logger/lib/http_response_log.dart @@ -1,4 +1,4 @@ -import 'dart:convert' show JsonEncoder; +import 'dart:convert' show JsonEncoder, jsonDecode; import 'package:http_interceptor/http_interceptor.dart'; import 'package:meta/meta.dart'; @@ -37,7 +37,7 @@ class HttpResponseLog extends TalkerLog with ResponseTime { final StringBuffer msg = StringBuffer(); msg.write('[$title]'); msg.write(' [${response.request?.method}]'); - msg.write(' $message'); + msg.writeln(' $message'); final String? data = switch (response) { Response res => res.body, @@ -47,7 +47,8 @@ class HttpResponseLog extends TalkerLog with ResponseTime { msg.writeln('Status: ${response.statusCode}'); if (settings.printResponseTime) { - final int? responseTime = getResponseTime(response.headers); + final int? responseTime = getResponseTime(response.headers) ?? + getResponseTime(response.request?.headers); if (responseTime != null) { msg.writeln('Time: $responseTime ms'); @@ -72,8 +73,10 @@ class HttpResponseLog extends TalkerLog with ResponseTime { msg.writeln('Redirect: ${response.isRedirect}'); } - if (settings.printResponseData && data != null) { + if (settings.printResponseData && (data?.isNotEmpty ?? false)) { try { + msg.writeln('Data: ${convert(jsonDecode(data!))}'); + } on FormatException { msg.writeln('Data: ${convert(data)}'); } catch (error, stackTrace) { msg.writeln( diff --git a/packages/talker_http_logger/lib/response_time.dart b/packages/talker_http_logger/lib/response_time.dart index 01f8b5ac7..b9acfd3e8 100644 --- a/packages/talker_http_logger/lib/response_time.dart +++ b/packages/talker_http_logger/lib/response_time.dart @@ -2,9 +2,9 @@ import 'package:talker/talker.dart'; import 'package:talker_http_logger/talker_http_logger_interceptor.dart'; mixin ResponseTime on TalkerLog { - int? getResponseTime(Map headers) { + int? getResponseTime(Map? headers) { final int? triggerTime = - int.tryParse(headers[TalkerHttpLogger.kLogsTimeStamp] ?? ''); + int.tryParse(headers?[TalkerHttpLogger.kLogsTimeStamp] ?? ''); if (triggerTime != null && triggerTime > 0) { return DateTime.timestamp().millisecondsSinceEpoch - triggerTime; diff --git a/packages/talker_http_logger/test/logger_test.dart b/packages/talker_http_logger/test/logger_test.dart new file mode 100644 index 000000000..44ebc09f9 --- /dev/null +++ b/packages/talker_http_logger/test/logger_test.dart @@ -0,0 +1,368 @@ +import 'dart:convert'; + +import 'package:http_interceptor/http_interceptor.dart'; +import 'package:talker/talker.dart'; +import 'package:talker_http_logger/http_error_log.dart'; +import 'package:talker_http_logger/http_request_log.dart'; +import 'package:talker_http_logger/http_response_log.dart'; +import 'package:talker_http_logger/talker_http_logger_interceptor.dart'; +import 'package:test/test.dart'; + +void main() { + group('TalkerHttpLogger tests', () { + late TalkerHttpLogger logger; + late Talker talker; + late Request fakeRequest; + + setUp(() { + talker = Talker(settings: TalkerSettings(useConsoleLogs: false)); + logger = TalkerHttpLogger(talker: talker); + fakeRequest = Request(HttpMethod.GET.name, Uri.parse('/test')); + }); + + test('configure method should update logger settings', () { + logger.configure(printRequestData: true); + expect(logger.settings.printRequestData, true); + }); + + test('interceptRequest method should log http GET request', () async { + logger.configure(printRequestHeaders: true); + + await logger.interceptRequest(request: fakeRequest); + + expect(talker.history.firstOrNull?.message, fakeRequest.url.toString()); + expect(talker.history.firstOrNull, isA()); + expect( + talker.history.firstOrNull?.generateTextMessage(), + '[http-request] [GET] /test', + ); + }); + + test('interceptRequest method should log http POST request', () async { + logger.configure(printRequestHeaders: true); + + final Request postRequest = fakeRequest.copyWith( + method: HttpMethod.POST, + headers: { + 'Content-Type': 'application/json; charset=utf-8', + }, + body: jsonEncode({ + 'foo': 'bar', + 'baz': 'qux', + }), + ); + + await logger.interceptRequest(request: postRequest); + + expect(talker.history.firstOrNull?.message, postRequest.url.toString()); + expect(talker.history.firstOrNull, isA()); + expect( + talker.history.firstOrNull?.generateTextMessage(), + '''[http-request] [POST] /test +Headers: { + "content-type": "application/json; charset=utf-8" +} +Data: { + "foo": "bar", + "baz": "qux" +}''', + ); + }); + + test('interceptRequest method should log http PUT request', () async { + logger.configure(printRequestHeaders: true); + + final Request putRequest = fakeRequest.copyWith( + method: HttpMethod.PUT, + headers: { + 'Content-Type': 'application/json; charset=utf-8', + }, + body: jsonEncode({ + 'foo': 'bar', + 'baz': 'qux', + }), + ); + + await logger.interceptRequest(request: putRequest); + + expect(talker.history.firstOrNull?.message, putRequest.url.toString()); + expect(talker.history.firstOrNull, isA()); + expect( + talker.history.firstOrNull?.generateTextMessage(), + '''[http-request] [PUT] /test +Headers: { + "content-type": "application/json; charset=utf-8" +} +Data: { + "foo": "bar", + "baz": "qux" +}''', + ); + }); + + test('interceptRequest method should log http PATCH request', () async { + logger.configure(printRequestHeaders: true); + + final Request putRequest = fakeRequest.copyWith( + method: HttpMethod.PATCH, + headers: { + 'Content-Type': 'application/json; charset=utf-8', + }, + body: jsonEncode({ + 'foo': 'bar', + 'baz': 'qux', + }), + ); + + await logger.interceptRequest(request: putRequest); + + expect(talker.history.firstOrNull?.message, putRequest.url.toString()); + expect(talker.history.firstOrNull, isA()); + expect( + talker.history.firstOrNull?.generateTextMessage(), + '''[http-request] [PATCH] /test +Headers: { + "content-type": "application/json; charset=utf-8" +} +Data: { + "foo": "bar", + "baz": "qux" +}''', + ); + }); + + test('interceptRequest method should log http DELETE request', () async { + logger.configure(printRequestHeaders: true); + + final Request deleteRequest = + fakeRequest.copyWith(method: HttpMethod.DELETE); + + await logger.interceptRequest(request: deleteRequest); + + expect(talker.history.firstOrNull?.message, deleteRequest.url.toString()); + expect(talker.history.firstOrNull, isA()); + expect( + talker.history.firstOrNull?.generateTextMessage(), + '''[http-request] [DELETE] /test +Headers: { + "content-type": "text/plain; charset=utf-8" +}''', + ); + }); + + test('interceptRequest method should log http HEAD request', () async { + logger.configure(printRequestHeaders: true); + + final Request headRequest = fakeRequest.copyWith(method: HttpMethod.HEAD); + + await logger.interceptRequest(request: headRequest); + + expect(talker.history.firstOrNull?.message, headRequest.url.toString()); + expect(talker.history.firstOrNull, isA()); + expect( + talker.history.firstOrNull?.generateTextMessage(), + '''[http-request] [HEAD] /test +Headers: { + "content-type": "text/plain; charset=utf-8" +}''', + ); + }); + + test('interceptResponse method should log http response', () async { + final Response fakeResponse = + Response('responseBody', 200, request: fakeRequest); + + final String logMessage = + fakeResponse.request?.url.toString() ?? fakeRequest.url.toString(); + + await logger.interceptResponse(response: fakeResponse); + + expect(talker.history.lastOrNull?.message, logMessage); + expect(talker.history.lastOrNull, isA()); + expect( + talker.history.lastOrNull?.generateTextMessage(), + '''[http-response] [GET] /test +Status: 200 +Data: "responseBody"''', + ); + }); + + test('interceptResponse method should log http 4xx response error', + () async { + final Response fakeResponse = + Response('responseErrorBody', 400, request: fakeRequest); + + await logger.interceptResponse(response: fakeResponse); + + expect(talker.history, isNotEmpty); + expect(talker.history.lastOrNull, isA()); + expect( + talker.history.lastOrNull?.generateTextMessage(), + '''[http-error] [GET] /test +Status: 400 +Data: "responseErrorBody"''', + ); + }); + + test('interceptResponse method should log http 5xx response error', + () async { + final Response fakeResponse = + Response('responseErrorBody', 500, request: fakeRequest); + + await logger.interceptResponse(response: fakeResponse); + + expect(talker.history, isNotEmpty); + expect(talker.history.lastOrNull, isA()); + expect( + talker.history.lastOrNull?.generateTextMessage(), + '''[http-error] [GET] /test +Status: 500 +Data: "responseErrorBody"''', + ); + }); + + test('interceptResponse method should log http response headers', () async { + logger.configure(printResponseHeaders: true); + + final Response fakeResponse = Response( + '', + 200, + headers: {'HEADER': 'VALUE'}, + request: fakeRequest, + ); + + await logger.interceptResponse(response: fakeResponse); + + expect( + talker.history.lastOrNull?.generateTextMessage(), + '''[http-response] [GET] /test +Status: 200 +Headers: { + "HEADER": "VALUE" +}''', + ); + }); + + test( + 'interceptRequest method should hide specific header values in logging', + () async { + logger.configure( + printRequestHeaders: true, + hiddenHeaders: {'Authorization'}, + ); + + await logger.interceptRequest( + request: fakeRequest.copyWith( + headers: { + "firstHeader": "firstHeaderValue", + "authorization": "bearer super_secret_token", + "lastHeader": "lastHeaderValue", + }, + ), + ); + + expect( + talker.history.firstOrNull?.generateTextMessage(), + '''[http-request] [GET] /test +Headers: { + "content-type": "text/plain; charset=utf-8", + "firstHeader": "firstHeaderValue", + "authorization": "*****", + "lastHeader": "lastHeaderValue" +}''', + ); + }); + + test('interceptResponse should show response time when requested', + () async { + logger.configure(printResponseTime: true); + + final Response fakeResponse = Response( + 'responseBody', + 200, + request: fakeRequest.copyWith( + headers: { + TalkerHttpLogger.kLogsTimeStamp: + (DateTime.timestamp().millisecondsSinceEpoch - 69).toString(), + }, + ), + ); + + await logger.interceptResponse(response: fakeResponse); + + final String? log = talker.history.lastOrNull?.generateTextMessage(); + expect(log, isNotNull); + expect(log, isA()); + expect(log, contains('[http-response] [GET] /test')); + expect(log, contains('Status: 200')); + expect(log, matches(RegExp(r'Time: \d+ ms'))); + expect(log, contains('Data: "responseBody"')); + }); + + test( + 'interceptResponse should show response time in error when requested', + () async { + logger.configure(printResponseTime: true); + + final Response fakeResponse = + Response('responseErrorBody', 400, request: fakeRequest) + .copyWith(headers: { + TalkerHttpLogger.kLogsTimeStamp: + (DateTime.timestamp().millisecondsSinceEpoch - 69).toString(), + }); + + await logger.interceptResponse(response: fakeResponse); + + final String? log = talker.history.lastOrNull?.generateTextMessage(); + expect(log, isNotNull); + expect(log, isA()); + expect(log, contains('[http-error] [GET] /test')); + expect(log, contains('Status: 400')); + expect(log, matches(RegExp(r'Time: \d+ ms'))); + expect(log, contains('Data: "responseErrorBody"')); + }, + ); + + test('interceptRequest should not log if logger is disabled', () async { + logger.configure(enabled: false); + + await logger.interceptRequest(request: fakeRequest); + + expect(talker.history, isEmpty); + }); + + test( + 'interceptRequest should not log if request and response are filtered', + () async { + logger.configure( + requestFilter: (_) => false, + responseFilter: (_) => false, + ); + + await logger.interceptRequest(request: fakeRequest); + + expect(talker.history, isEmpty); + }, + ); + + test( + 'interceptResponse should not log if error is filtered', + () async { + logger.configure( + requestFilter: (_) => false, + errorFilter: (_) => false, + ); + + await logger.interceptResponse( + response: Response( + 'responseErrorBodyBase', + 400, + request: fakeRequest, + ), + ); + + expect(talker.history, isEmpty); + }, + ); + }); +} diff --git a/packages/talker_http_logger/test/logs_test.dart b/packages/talker_http_logger/test/logs_test.dart new file mode 100644 index 000000000..dbc6b747c --- /dev/null +++ b/packages/talker_http_logger/test/logs_test.dart @@ -0,0 +1,748 @@ +import 'dart:convert'; + +import 'package:http_interceptor/http_interceptor.dart'; +import 'package:talker/talker.dart'; +import 'package:talker_http_logger/curl_request.dart'; +import 'package:talker_http_logger/http_error_log.dart'; +import 'package:talker_http_logger/http_request_log.dart'; +import 'package:talker_http_logger/http_response_log.dart'; +import 'package:talker_http_logger/talker_http_logger.dart'; +import 'package:test/test.dart'; + +class _MockHttpRequestLog extends HttpRequestLog { + _MockHttpRequestLog( + super.title, { + required super.request, + required super.settings, + }); + + @override + String convert(Object? object) => throw Exception('forced error'); +} + +class _MockHttpResponseLog extends HttpResponseLog { + _MockHttpResponseLog( + super.title, { + required super.response, + required super.settings, + }); + + @override + String convert(Object? object) => throw Exception('forced error'); +} + +void main() { + late Request request; + + setUp(() { + request = Request(HttpMethod.GET.name, Uri.parse('/test')); + }); + + group('HttpRequestLog', () { + test('generateTextMessage should include method and message', () { + final HttpRequestLog log = HttpRequestLog( + 'Test message', + request: request, + settings: TalkerHttpLoggerSettings( + requestPen: AnsiPen()..blue(), + ), + ); + + expect( + log.generateTextMessage(), + contains('[GET] Test message'), + ); + }); + + test( + 'generateTextMessage should include data if printRequestData is true', + () { + final HttpRequestLog log = HttpRequestLog( + null, + request: request.copyWith( + method: HttpMethod.POST, + body: jsonEncode({ + 'foo': 'bar', + 'baz': 'qux', + }), + ), + settings: const TalkerHttpLoggerSettings(printRequestData: true), + ); + + expect( + log.generateTextMessage(), + contains( + '''Data: { + "foo": "bar", + "baz": "qux" +}''', + ), + ); + }, + ); + + test( + 'generateTextMessage with BaseRequest should include form data if printRequestData is true', + () { + final HttpRequestLog log = HttpRequestLog( + null, + request: request.copyWith( + method: HttpMethod.POST, + body: jsonEncode({ + 'foo': 'bar', + 'baz': 'qux', + }), + ), + settings: const TalkerHttpLoggerSettings(printRequestData: true), + ); + + expect( + log.generateTextMessage(), + contains( + '''Data: { + "foo": "bar", + "baz": "qux" +}''', + ), + ); + }, + ); + + test( + 'generateTextMessage should include headers if printRequestHeaders is true', + () { + final HttpRequestLog log = HttpRequestLog( + null, + request: request.copyWith( + headers: {'Authorization': 'Bearer Token'}, + ), + settings: const TalkerHttpLoggerSettings(printRequestHeaders: true), + ); + + expect( + log.generateTextMessage(), + contains('"Authorization": "Bearer Token"'), + ); + }, + ); + + test( + 'generateTextMessage should include redirect if printResponseRedirects is true', + () { + final HttpResponseLog log = HttpResponseLog( + '', + response: Response( + '', + 200, + request: request, + isRedirect: true, + ), + settings: const TalkerHttpLoggerSettings( + printResponseRedirects: true, + ), + ); + + expect(log.generateTextMessage(), contains('Redirect: true')); + }, + ); + + test( + 'generateTextMessage should not include redirects if printResponseRedirects is false', + () { + final HttpResponseLog log = HttpResponseLog( + '', + response: Response( + '', + 200, + request: request, + isRedirect: true, + ), + settings: const TalkerHttpLoggerSettings( + printResponseRedirects: false, + ), + ); + + final result = log.generateTextMessage(); + expect(result.contains('Redirect:'), isFalse); + }, + ); + + test( + 'generateTextMessage should include curl command if printRequestCurl is true', + () { + final HttpRequestLog log = HttpRequestLog( + null, + request: request, + settings: const TalkerHttpLoggerSettings(printRequestCurl: true), + ); + + final String out = log.generateTextMessage(); + + expect(out, contains('[cURL]')); + expect(out, contains('curl -v')); + expect(out, contains('-X ${request.method}')); + expect(out, contains('${request.url}')); + expect(out, contains('[cURL] ${request.toCurl()}')); + }, + ); + + test( + 'generateTextMessage should include curl command with headers if printRequestCurl is true', + () { + final Request requestWithHeaders = request.copyWith( + headers: { + 'foo': 'bar', + 'baz': 'qux', + }, + ); + + final HttpRequestLog log = HttpRequestLog( + null, + request: requestWithHeaders, + settings: const TalkerHttpLoggerSettings( + printRequestCurl: true, + hiddenHeaders: {'baz'}, + ), + ); + + final String out = log.generateTextMessage(); + + expect(out, contains('[cURL]')); + expect(out, contains('curl -v')); + expect(out, contains('-X ${requestWithHeaders.method}')); + expect(out, contains("-H 'foo: bar'")); + expect(out, isNot(contains("-H 'baz: qux'"))); + expect(out, contains("-H 'baz: *****'")); + expect(out, contains('${requestWithHeaders.url}')); + expect( + out, + contains( + '[cURL] ${requestWithHeaders.copyWith(headers: { + ...requestWithHeaders.headers, + 'baz': '*****', + }).toCurl()}', + ), + ); + }, + ); + + test( + 'generateTextMessage should include curl command with body if printRequestCurl is true', + () { + final Request postRequest = request.copyWith( + method: HttpMethod.POST, + body: jsonEncode({ + 'foo': 'bar', + 'baz': 'qux', + }), + ); + + final HttpRequestLog log = HttpRequestLog( + null, + request: postRequest, + settings: const TalkerHttpLoggerSettings(printRequestCurl: true), + ); + + final String out = log.generateTextMessage(); + + expect(out, contains('[cURL]')); + expect(out, contains('curl -v')); + expect(out, contains('-X ${postRequest.method}')); + expect(out, contains(r"""-d '{"foo":"bar","baz":"qux"}'""")); + expect(out, contains('${postRequest.url}')); + expect(out, contains('[cURL] ${postRequest.toCurl()}')); + }, + ); + + test( + 'generateTextMessage with baseRequest should include curl command with form data if printRequestCurl is true', + () { + final BaseRequest postRequest = request.copyWith( + method: HttpMethod.POST, + headers: { + 'content-type': 'application/json; charset=utf-8', + }, + body: jsonEncode({ + 'foo': 'bar', + 'baz': 'qux', + }), + ); + + final HttpRequestLog log = HttpRequestLog( + null, + request: postRequest, + settings: const TalkerHttpLoggerSettings(printRequestCurl: true), + ); + + final String out = log.generateTextMessage(); + + expect(out, contains('[cURL]')); + expect(out, contains('curl -v')); + expect(out, contains('-X ${postRequest.method}')); + expect( + out, + contains( + "-H 'content-type: application/json; charset=utf-8'", + ), + ); + expect(out, contains("""-d '{"foo":"bar","baz":"qux"}'""")); + expect(out, contains('${postRequest.url}')); + expect(out, contains('[cURL] ${postRequest.toCurl()}')); + }, + ); + + test('logLevel should return settings logLevel', () { + final HttpRequestLog log = HttpRequestLog( + 'Test message', + request: request, + settings: const TalkerHttpLoggerSettings(logLevel: LogLevel.info), + ); + + expect(log.logLevel, equals(LogLevel.info)); + }); + + test('force throw exception on convert headers', () { + final HttpRequestLog log = _MockHttpRequestLog( + 'Test message', + request: request.copyWith(headers: { + 'foo': 'bar', + 'baz': 'qux', + }), + settings: const TalkerHttpLoggerSettings(printRequestHeaders: true), + ); + + expect(() => log.convert('foo'), throwsA(isA())); + + expect(() => log.generateTextMessage(), returnsNormally); + + final String result = log.generateTextMessage(); + expect(result, contains('[GET] Test message')); + expect(result, contains('Headers: log.convert('foo'), throwsA(isA())); + + expect(() => log.generateTextMessage(), returnsNormally); + + final String result = log.generateTextMessage(); + expect(result, contains('[POST] Test message')); + expect(result, contains('Data: log.convert('foo'), throwsA(isA())); + + expect(() => log.generateTextMessage(), returnsNormally); + + final String result = log.generateTextMessage(); + expect(result, contains('[POST] Test message')); + expect(result, contains('Data: log.convert('foo'), throwsA(isA())); + + expect(() => log.generateTextMessage(), returnsNormally); + + final String result = log.generateTextMessage(); + expect(result, contains('[POST] Test message')); + expect(result, contains('Data: { + 'content-type': 'application/json', + }, + ), + settings: TalkerHttpLoggerSettings( + responsePen: AnsiPen()..blue(), + ), + ); + + final String result = log.generateTextMessage(); + + expect(log.pen, isNotNull); + expect(result, contains('[GET] Test message')); + expect(result, contains('Status: 200')); + expect(result, contains('Data: {\n "key": "value"\n}')); + }); + + test( + 'generateTextMessage should include message if printResponseMessage is true', + () { + final HttpResponseLog log = HttpResponseLog( + 'Test message', + response: Response( + 'responseBodyBase', + 200, + request: request, + reasonPhrase: 'OK', + ), + settings: const TalkerHttpLoggerSettings(printResponseMessage: true), + ); + + expect(log.generateTextMessage(), contains('Message: OK')); + }, + ); + + test( + 'generateTextMessage should include response time if printResponseTime is true', + () { + final HttpResponseLog log = HttpResponseLog( + 'Test message', + response: Response( + 'responseBodyBase', + 200, + request: request, + reasonPhrase: 'OK', + headers: { + TalkerHttpLogger.kLogsTimeStamp: + (DateTime.timestamp().millisecondsSinceEpoch - 123) + .toString(), + }, + ), + settings: const TalkerHttpLoggerSettings(printResponseTime: true), + ); + + expect(log.generateTextMessage(), matches(RegExp(r'Time: \d+ ms'))); + }, + ); + + test( + 'generateTextMessage should not include response time if printResponseTime is false', + () { + final HttpResponseLog log = HttpResponseLog( + 'Test message', + response: Response( + 'responseBodyBase', + 200, + request: request, + reasonPhrase: 'OK', + headers: { + TalkerHttpLogger.kLogsTimeStamp: + (DateTime.timestamp().millisecondsSinceEpoch - 123) + .toString(), + }, + ), + settings: const TalkerHttpLoggerSettings(printResponseTime: false), + ); + + expect(log.generateTextMessage(), isNot(contains('Time:'))); + }, + ); + + test( + 'generateTextMessage error should include include response time if printResponseTime is true', + () { + final HttpResponseLog log = HttpResponseLog( + 'Error title', + response: Response( + 'responseErrorBodyBase', + 404, + request: request, + reasonPhrase: 'Error message', + headers: { + TalkerHttpLogger.kLogsTimeStamp: + (DateTime.timestamp().millisecondsSinceEpoch - 123).toString(), + }, + ), + settings: const TalkerHttpLoggerSettings(printResponseTime: true), + ); + + expect(log.generateTextMessage(), matches(RegExp(r'Time: \d+ ms'))); + }); + + test('logLevel should return settings logLevel', () { + final HttpResponseLog log = HttpResponseLog( + 'Test message', + response: Response( + 'responseBodyBase', + 200, + request: request, + reasonPhrase: 'OK', + ), + settings: const TalkerHttpLoggerSettings(logLevel: LogLevel.warning), + ); + + expect(log.logLevel, equals(LogLevel.warning)); + }); + + test('force throw exception on convert Response headers', () { + final HttpResponseLog log = _MockHttpResponseLog( + 'Test message', + response: Response( + jsonEncode({ + 'foo': 'bar', + 'baz': 'qux', + }), + 200, + request: request, + headers: { + 'content-type': 'application/json', + }, + reasonPhrase: 'OK', + ), + settings: const TalkerHttpLoggerSettings(printResponseHeaders: true), + ); + + expect(() => log.convert('foo'), throwsA(isA())); + + expect(() => log.generateTextMessage(), returnsNormally); + + final String result = log.generateTextMessage(); + expect(result, contains('[GET] Test message')); + expect(result, contains('Headers: log.convert('foo'), throwsA(isA())); + + expect(() => log.generateTextMessage(), returnsNormally); + + final String result = log.generateTextMessage(); + expect(result, contains('[GET] Test message')); + expect(result, contains('Data: Date: Mon, 5 May 2025 08:18:08 +0100 Subject: [PATCH 14/30] :white_check_mark: increase test coverage --- packages/talker_http_logger/pubspec.yaml | 1 + .../helpers/multipart_request_extension.dart | 29 ++++ .../talker_http_logger/test/logs_test.dart | 126 ++++++++++++++++++ 3 files changed, 156 insertions(+) create mode 100644 packages/talker_http_logger/test/helpers/multipart_request_extension.dart diff --git a/packages/talker_http_logger/pubspec.yaml b/packages/talker_http_logger/pubspec.yaml index 466bc32cc..f8006ccfa 100644 --- a/packages/talker_http_logger/pubspec.yaml +++ b/packages/talker_http_logger/pubspec.yaml @@ -13,5 +13,6 @@ dependencies: talker: ^4.7.5 dev_dependencies: + http_parser: ^4.1.2 lints: ^5.1.1 test: ^1.25.15 diff --git a/packages/talker_http_logger/test/helpers/multipart_request_extension.dart b/packages/talker_http_logger/test/helpers/multipart_request_extension.dart new file mode 100644 index 000000000..a5763f7ca --- /dev/null +++ b/packages/talker_http_logger/test/helpers/multipart_request_extension.dart @@ -0,0 +1,29 @@ +import 'package:http_interceptor/http_interceptor.dart'; + +extension MultipartRequestExtension on Request { + MultipartRequest toMultipartRequest( + Iterable<({String name, dynamic value})> parts, + ) { + final MultipartRequest request = MultipartRequest(method, url) + ..headers.addAll(headers); + + for (final ({String name, dynamic value}) part in parts) { + if (part.value == null) continue; + + if (part.value is MultipartFile) { + request.files.add(part.value); + } else if (part.value is Iterable) { + request.files.addAll(part.value); + } else if (part.value is Iterable) { + request.fields.addAll({ + for (int i = 0; i < part.value.length; i++) + '${part.name}[$i]': part.value.elementAt(i).toString(), + }); + } else { + request.fields[part.name] = part.value.toString(); + } + } + + return request; + } +} diff --git a/packages/talker_http_logger/test/logs_test.dart b/packages/talker_http_logger/test/logs_test.dart index dbc6b747c..8d4e4ed58 100644 --- a/packages/talker_http_logger/test/logs_test.dart +++ b/packages/talker_http_logger/test/logs_test.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'package:http_interceptor/http_interceptor.dart'; +import 'package:http_parser/http_parser.dart'; import 'package:talker/talker.dart'; import 'package:talker_http_logger/curl_request.dart'; import 'package:talker_http_logger/http_error_log.dart'; @@ -9,6 +10,8 @@ import 'package:talker_http_logger/http_response_log.dart'; import 'package:talker_http_logger/talker_http_logger.dart'; import 'package:test/test.dart'; +import 'helpers/multipart_request_extension.dart'; + class _MockHttpRequestLog extends HttpRequestLog { _MockHttpRequestLog( super.title, { @@ -81,6 +84,60 @@ void main() { }, ); + test( + 'generateTextMessage with multipart request should include form data if printRequestData is true', + () { + final BaseRequest multiPartRequest = + request.copyWith(method: HttpMethod.POST).toMultipartRequest([ + (name: '1', value: {'foo': 'bar'}), + (name: '2', value: {'baz': 'qux'}), + ]); + + final HttpRequestLog log = HttpRequestLog( + null, + request: multiPartRequest, + settings: const TalkerHttpLoggerSettings(printRequestData: true), + ); + + expect( + log.generateTextMessage(), + contains( + '''Data: { + "1": "{foo: bar}", + "2": "{baz: qux}" +}''', + ), + ); + }, + ); + + test( + 'generateTextMessage with multipart file request should include form data if printRequestData is true', + () { + final MultipartFile file = MultipartFile.fromBytes( + 'foo_bar', + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + filename: 'baz_qux', + contentType: MediaType.parse('application/octet-stream'), + ); + + final BaseRequest multiPartRequest = request + .copyWith(method: HttpMethod.POST) + .toMultipartRequest([(name: 'file', value: file)]); + + final HttpRequestLog log = HttpRequestLog( + null, + request: multiPartRequest, + settings: const TalkerHttpLoggerSettings(printRequestData: true), + ); + + expect( + log.generateTextMessage(), + contains('Data: {\n "foo_bar": "baz_qux"\n}'), + ); + }, + ); + test( 'generateTextMessage with BaseRequest should include form data if printRequestData is true', () { @@ -291,6 +348,75 @@ void main() { }, ); + test( + 'generateTextMessage with multipart baseRequest should include curl command with form data if printRequestCurl is true', + () { + final List<({String name, Map value})> parts = [ + (name: '1', value: {'foo': 'bar'}), + (name: '2', value: {'baz': 'qux'}), + ]; + + final BaseRequest multiPartRequest = + request.copyWith(method: HttpMethod.POST).toMultipartRequest(parts); + + final HttpRequestLog log = HttpRequestLog( + null, + request: multiPartRequest, + settings: const TalkerHttpLoggerSettings(printRequestCurl: true), + ); + + final String out = log.generateTextMessage(); + + expect(out, contains('[cURL]')); + expect(out, contains('curl -v')); + expect(out, contains('-X ${multiPartRequest.method}')); + for (final ({String name, Map value}) part in parts) { + expect(out, contains("-F '${part.name}=${part.value}'")); + } + expect(out, contains('${multiPartRequest.url}')); + expect(out, contains('[cURL] ${multiPartRequest.toCurl()}')); + }, + ); + + test( + 'generateTextMessage with multipart file request should include curl command with form data if printRequestCurl is true', + () async { + final MultipartFile file = MultipartFile.fromBytes( + 'foo_bar', + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + filename: 'baz_qux', + contentType: MediaType.parse('application/octet-stream'), + ); + + final List<({String name, MultipartFile value})> parts = [ + (name: 'file', value: file), + ]; + + final BaseRequest multiPartRequest = + request.copyWith(method: HttpMethod.POST).toMultipartRequest(parts); + + final HttpRequestLog log = HttpRequestLog( + null, + request: multiPartRequest, + settings: const TalkerHttpLoggerSettings(printRequestCurl: true), + ); + + final String out = log.generateTextMessage(); + + expect(out, contains('[cURL]')); + expect(out, contains('curl -v')); + expect(out, contains('-X ${multiPartRequest.method}')); + for (final ({String name, MultipartFile value}) part in parts) { + expect( + out, + contains("-F '${part.value.field}=@${part.value.filename}'"), + ); + } + expect(out, contains('${multiPartRequest.url}')); + expect(out, contains('[cURL] ${multiPartRequest.toCurl()}')); + }, + ); + test('logLevel should return settings logLevel', () { final HttpRequestLog log = HttpRequestLog( 'Test message', From 5f74d765cf7fce7b7f03564ad8ccc2c686052a4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Mon, 5 May 2025 08:57:57 +0100 Subject: [PATCH 15/30] :white_check_mark: increase test coverage --- packages/talker_http_logger/pubspec.yaml | 1 + .../talker_http_logger/test/logger_test.dart | 30 +++++++++++++++++ .../talker_http_logger/test/logs_test.dart | 32 +++++++++++++++++++ 3 files changed, 63 insertions(+) diff --git a/packages/talker_http_logger/pubspec.yaml b/packages/talker_http_logger/pubspec.yaml index f8006ccfa..08ec6fa6c 100644 --- a/packages/talker_http_logger/pubspec.yaml +++ b/packages/talker_http_logger/pubspec.yaml @@ -14,5 +14,6 @@ dependencies: dev_dependencies: http_parser: ^4.1.2 + qs_dart: ^1.3.5+1 lints: ^5.1.1 test: ^1.25.15 diff --git a/packages/talker_http_logger/test/logger_test.dart b/packages/talker_http_logger/test/logger_test.dart index 44ebc09f9..9f9b77ca6 100644 --- a/packages/talker_http_logger/test/logger_test.dart +++ b/packages/talker_http_logger/test/logger_test.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'package:http_interceptor/http_interceptor.dart'; +import 'package:qs_dart/qs_dart.dart' as qs; import 'package:talker/talker.dart'; import 'package:talker_http_logger/http_error_log.dart'; import 'package:talker_http_logger/http_request_log.dart'; @@ -69,6 +70,35 @@ Data: { ); }); + test('interceptRequest method should log http POST request form data', + () async { + logger.configure(printRequestHeaders: true); + + final Request postRequest = fakeRequest.copyWith( + method: HttpMethod.POST, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8', + }, + body: qs.encode({ + 'foo': 'bar', + 'baz': 'qux', + }), + ); + + await logger.interceptRequest(request: postRequest); + + expect(talker.history.firstOrNull?.message, postRequest.url.toString()); + expect(talker.history.firstOrNull, isA()); + expect( + talker.history.firstOrNull?.generateTextMessage(), + '''[http-request] [POST] /test +Headers: { + "content-type": "application/x-www-form-urlencoded; charset=utf-8" +} +Data: foo=bar&baz=qux''', + ); + }); + test('interceptRequest method should log http PUT request', () async { logger.configure(printRequestHeaders: true); diff --git a/packages/talker_http_logger/test/logs_test.dart b/packages/talker_http_logger/test/logs_test.dart index 8d4e4ed58..a508252a8 100644 --- a/packages/talker_http_logger/test/logs_test.dart +++ b/packages/talker_http_logger/test/logs_test.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'package:http_interceptor/http_interceptor.dart'; import 'package:http_parser/http_parser.dart'; +import 'package:qs_dart/qs_dart.dart' as qs; import 'package:talker/talker.dart'; import 'package:talker_http_logger/curl_request.dart'; import 'package:talker_http_logger/http_error_log.dart'; @@ -311,6 +312,37 @@ void main() { }, ); + test( + 'generateTextMessage should include curl command with form body if printRequestCurl is true', + () { + final Request postRequest = request.copyWith( + method: HttpMethod.POST, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8', + }, + body: qs.encode({ + 'foo': 'bar', + 'baz': 'qux', + }), + ); + + final HttpRequestLog log = HttpRequestLog( + null, + request: postRequest, + settings: const TalkerHttpLoggerSettings(printRequestCurl: true), + ); + + final String out = log.generateTextMessage(); + + expect(out, contains('[cURL]')); + expect(out, contains('curl -v')); + expect(out, contains('-X ${postRequest.method}')); + expect(out, contains(r"""-d 'foo=bar&baz=qux'""")); + expect(out, contains('${postRequest.url}')); + expect(out, contains('[cURL] ${postRequest.toCurl()}')); + }, + ); + test( 'generateTextMessage with baseRequest should include curl command with form data if printRequestCurl is true', () { From 5059add0542002e10542fed690febbfbc6903a02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Mon, 5 May 2025 09:03:19 +0100 Subject: [PATCH 16/30] :white_check_mark: increase test coverage --- .../talker_http_logger/test/logs_test.dart | 38 ++++++++++--------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/packages/talker_http_logger/test/logs_test.dart b/packages/talker_http_logger/test/logs_test.dart index a508252a8..9fa52a1f9 100644 --- a/packages/talker_http_logger/test/logs_test.dart +++ b/packages/talker_http_logger/test/logs_test.dart @@ -609,13 +609,14 @@ void main() { response: Response( 'responseBodyBase', 200, - request: request, + request: request.copyWith( + headers: { + TalkerHttpLogger.kLogsTimeStamp: + (DateTime.timestamp().millisecondsSinceEpoch - 123) + .toString(), + }, + ), reasonPhrase: 'OK', - headers: { - TalkerHttpLogger.kLogsTimeStamp: - (DateTime.timestamp().millisecondsSinceEpoch - 123) - .toString(), - }, ), settings: const TalkerHttpLoggerSettings(printResponseTime: true), ); @@ -632,13 +633,14 @@ void main() { response: Response( 'responseBodyBase', 200, - request: request, + request: request.copyWith( + headers: { + TalkerHttpLogger.kLogsTimeStamp: + (DateTime.timestamp().millisecondsSinceEpoch - 123) + .toString(), + }, + ), reasonPhrase: 'OK', - headers: { - TalkerHttpLogger.kLogsTimeStamp: - (DateTime.timestamp().millisecondsSinceEpoch - 123) - .toString(), - }, ), settings: const TalkerHttpLoggerSettings(printResponseTime: false), ); @@ -655,12 +657,14 @@ void main() { response: Response( 'responseErrorBodyBase', 404, - request: request, + request: request.copyWith( + headers: { + TalkerHttpLogger.kLogsTimeStamp: + (DateTime.timestamp().millisecondsSinceEpoch - 123) + .toString(), + }, + ), reasonPhrase: 'Error message', - headers: { - TalkerHttpLogger.kLogsTimeStamp: - (DateTime.timestamp().millisecondsSinceEpoch - 123).toString(), - }, ), settings: const TalkerHttpLoggerSettings(printResponseTime: true), ); From c4d78235785b0a28f6406bade77e239ccefd791f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Mon, 5 May 2025 09:18:11 +0100 Subject: [PATCH 17/30] :white_check_mark: increase test coverage --- .../lib/talker_http_logger_interceptor.dart | 14 +++--- .../talker_http_logger/test/logger_test.dart | 50 +++++++++++++++---- 2 files changed, 46 insertions(+), 18 deletions(-) diff --git a/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart b/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart index 7548038bf..79795a77f 100644 --- a/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart +++ b/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart @@ -14,7 +14,7 @@ class TalkerHttpLogger extends InterceptorContract { _talker = talker ?? Talker(); } - static const String kLogsTimeStamp = '_talker_http_logger_ts_'; + static const String kLogsTimeStamp = 'x-talker-http-logger-ts'; late final Talker _talker; @@ -73,15 +73,15 @@ class TalkerHttpLogger extends InterceptorContract { required BaseRequest request, }) async { if (settings.enabled && (settings.requestFilter?.call(request) ?? true)) { + if (settings.printResponseTime) { + request.headers[kLogsTimeStamp] = + DateTime.timestamp().millisecondsSinceEpoch.toString(); + } + _talker.logCustom( HttpRequestLog( request.url.toString(), - request: switch (settings.printResponseTime) { - true => request - ..headers[kLogsTimeStamp] = - DateTime.timestamp().millisecondsSinceEpoch.toString(), - false => request - }, + request: request, settings: settings, ), ); diff --git a/packages/talker_http_logger/test/logger_test.dart b/packages/talker_http_logger/test/logger_test.dart index 9f9b77ca6..6e3a36125 100644 --- a/packages/talker_http_logger/test/logger_test.dart +++ b/packages/talker_http_logger/test/logger_test.dart @@ -303,19 +303,48 @@ Headers: { ); }); + test('interceptRequest should add timestamp to request headers', () async { + logger.configure(printResponseTime: true); + + await logger.interceptRequest(request: fakeRequest); + + expect(fakeRequest.headers[TalkerHttpLogger.kLogsTimeStamp], isNotNull); + expect( + fakeRequest.headers[TalkerHttpLogger.kLogsTimeStamp], + isA(), + ); + expect( + fakeRequest.headers[TalkerHttpLogger.kLogsTimeStamp], + matches(RegExp(r'^\d+$')), + ); + final int? ts = int.tryParse( + fakeRequest.headers[TalkerHttpLogger.kLogsTimeStamp] ?? '', + ); + expect(ts, isNotNull); + expect(ts, isNonNegative); + expect(ts, greaterThan(0)); + expect( + ts, + lessThanOrEqualTo(DateTime.timestamp().millisecondsSinceEpoch), + ); + + final String? log = talker.history.firstOrNull?.generateTextMessage(); + expect(log, isNotNull); + expect(log, isA()); + expect(log, contains('[http-request] [GET] /test')); + }); + test('interceptResponse should show response time when requested', () async { logger.configure(printResponseTime: true); + // Simulate a request with a timestamp + await logger.interceptRequest(request: fakeRequest); + final Response fakeResponse = Response( 'responseBody', 200, - request: fakeRequest.copyWith( - headers: { - TalkerHttpLogger.kLogsTimeStamp: - (DateTime.timestamp().millisecondsSinceEpoch - 69).toString(), - }, - ), + request: fakeRequest, ); await logger.interceptResponse(response: fakeResponse); @@ -334,12 +363,11 @@ Headers: { () async { logger.configure(printResponseTime: true); + // Simulate a request with a timestamp + await logger.interceptRequest(request: fakeRequest); + final Response fakeResponse = - Response('responseErrorBody', 400, request: fakeRequest) - .copyWith(headers: { - TalkerHttpLogger.kLogsTimeStamp: - (DateTime.timestamp().millisecondsSinceEpoch - 69).toString(), - }); + Response('responseErrorBody', 400, request: fakeRequest); await logger.interceptResponse(response: fakeResponse); From a009ae082cce3405caf03be4cad3194969972ad5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Mon, 5 May 2025 09:53:03 +0100 Subject: [PATCH 18/30] :white_check_mark: increase test coverage --- .../lib/http_error_log.dart | 23 +++- .../lib/http_response_log.dart | 2 +- .../lib/talker_http_logger_settings.dart | 4 +- .../talker_http_logger/test/logs_test.dart | 123 ++++++++++++++++++ 4 files changed, 145 insertions(+), 7 deletions(-) diff --git a/packages/talker_http_logger/lib/http_error_log.dart b/packages/talker_http_logger/lib/http_error_log.dart index 4989c85c1..180066246 100644 --- a/packages/talker_http_logger/lib/http_error_log.dart +++ b/packages/talker_http_logger/lib/http_error_log.dart @@ -41,11 +41,15 @@ class HttpErrorLog extends TalkerLog with ResponseTime { final StringBuffer msg = StringBuffer(); msg.write('[$title]'); + if (response?.request?.method != null || request?.method != null) { msg.write(' [${response?.request?.method ?? request?.method}]'); } + if (response?.request != null || request != null) { msg.writeln(' ${response?.request?.url ?? request?.url}'); + } else if (exception is ClientException) { + msg.writeln(' ${(exception as ClientException).uri}'); } else { msg.writeln(); } @@ -83,12 +87,23 @@ class HttpErrorLog extends TalkerLog with ResponseTime { }; if (settings.printErrorData && (data?.isNotEmpty ?? false)) { + late final dynamic jsonData; try { - msg.writeln('Data: ${convert(jsonDecode(data!))}'); - } on FormatException { - msg.writeln('Data: ${convert(data)}'); + jsonData = jsonDecode(data!); } catch (_) { - msg.writeln('Data: $data'); + jsonData = null; + } + + try { + if (jsonData != null) { + msg.writeln('Data: ${convert(jsonData)}'); + } else { + msg.writeln('Data: ${convert(data)}'); + } + } catch (error, stackTrace) { + msg.writeln( + 'Data: ', + ); } } diff --git a/packages/talker_http_logger/lib/http_response_log.dart b/packages/talker_http_logger/lib/http_response_log.dart index 9789905a1..ea4bdea78 100644 --- a/packages/talker_http_logger/lib/http_response_log.dart +++ b/packages/talker_http_logger/lib/http_response_log.dart @@ -3,8 +3,8 @@ import 'dart:convert' show JsonEncoder, jsonDecode; import 'package:http_interceptor/http_interceptor.dart'; import 'package:meta/meta.dart'; import 'package:talker/talker.dart'; -import 'package:talker_http_logger/talker_http_logger_settings.dart'; import 'package:talker_http_logger/response_time.dart'; +import 'package:talker_http_logger/talker_http_logger_settings.dart'; class HttpResponseLog extends TalkerLog with ResponseTime { HttpResponseLog( diff --git a/packages/talker_http_logger/lib/talker_http_logger_settings.dart b/packages/talker_http_logger/lib/talker_http_logger_settings.dart index ee84e4ea4..7a02713b4 100644 --- a/packages/talker_http_logger/lib/talker_http_logger_settings.dart +++ b/packages/talker_http_logger/lib/talker_http_logger_settings.dart @@ -1,8 +1,8 @@ +import 'package:equatable/equatable.dart'; import 'package:http_interceptor/http_interceptor.dart' show BaseRequest, BaseResponse; -import 'package:talker/talker.dart'; -import 'package:equatable/equatable.dart'; import 'package:talker/talker.dart' show AnsiPen, LogLevel; +import 'package:talker/talker.dart'; typedef RequestFilter = bool Function(BaseRequest request); typedef ResponseFilter = bool Function(BaseResponse response); diff --git a/packages/talker_http_logger/test/logs_test.dart b/packages/talker_http_logger/test/logs_test.dart index 9fa52a1f9..1305d3016 100644 --- a/packages/talker_http_logger/test/logs_test.dart +++ b/packages/talker_http_logger/test/logs_test.dart @@ -35,6 +35,22 @@ class _MockHttpResponseLog extends HttpResponseLog { String convert(Object? object) => throw Exception('forced error'); } +class _MockHttpErrorLog extends HttpErrorLog { + _MockHttpErrorLog( + super.title, { + // ignore: unused_element_parameter + super.request, + super.response, + required super.settings, + super.exception, + // ignore: unused_element_parameter + super.stackTrace, + }); + + @override + String convert(Object? object) => throw Exception('forced error'); +} + void main() { late Request request; @@ -764,6 +780,57 @@ void main() { ); }); + test( + 'generateTextMessage should still work without a request and with ClientException', + () { + final HttpErrorLog log = HttpErrorLog( + 'Error title', + exception: ClientException( + 'Error message', + request.url, + ), + settings: TalkerHttpLoggerSettings( + errorPen: AnsiPen()..blue(), + ), + ); + + expect( + log.generateTextMessage(), + contains('[log] /test\nMessage: Error message'), + ); + }); + + test( + 'generateTextMessage should still work without a request with Exception', + () { + final HttpErrorLog log = HttpErrorLog( + 'Error title', + exception: Exception('Error message'), + settings: TalkerHttpLoggerSettings( + errorPen: AnsiPen()..blue(), + ), + ); + + expect( + log.generateTextMessage(), + contains('[log]\nMessage: Exception: Error message'), + ); + }); + + test('generateTextMessage should still work without a anything', () { + final HttpErrorLog log = HttpErrorLog( + 'Error title', + settings: TalkerHttpLoggerSettings( + errorPen: AnsiPen()..blue(), + ), + ); + + expect( + log.generateTextMessage(), + contains('[log]'), + ); + }); + test( 'generateTextMessage should not include data, header and message if disabled', () { @@ -856,6 +923,62 @@ void main() { }, ); + test( + 'generateTextMessage should include data if response has raw data', + () { + final HttpErrorLog log = HttpErrorLog( + 'Error title', + exception: ClientException( + 'Error message', + request.url, + ), + response: Response( + 'Internal Server Error', + 500, + request: request, + reasonPhrase: 'Error message', + ), + settings: const TalkerHttpLoggerSettings(), + ); + + expect( + log.generateTextMessage(), + contains('Data: "Internal Server Error"'), + ); + }, + ); + + test( + 'generateTextMessage should include data if response has bad data', + () { + final HttpErrorLog log = _MockHttpErrorLog( + 'Error title', + exception: ClientException( + 'Error message', + request.url, + ), + response: Response( + 'Internal Server Error', + 500, + request: request, + reasonPhrase: 'Error message', + ), + settings: const TalkerHttpLoggerSettings(), + ); + + expect(() => log.convert('foo'), throwsA(isA())); + + expect(() => log.generateTextMessage(), returnsNormally); + + final String result = log.generateTextMessage(); + expect(result, contains('[GET] /test')); + expect(result, contains('Status: 500')); + expect(result, contains('Message: Error message')); + expect(result, contains('Data: Date: Mon, 5 May 2025 09:56:24 +0100 Subject: [PATCH 19/30] :white_check_mark: increase test coverage --- .../lib/talker_http_logger_interceptor.dart | 65 ++++++++----------- 1 file changed, 26 insertions(+), 39 deletions(-) diff --git a/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart b/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart index 79795a77f..0c5b9dc16 100644 --- a/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart +++ b/packages/talker_http_logger/lib/talker_http_logger_interceptor.dart @@ -96,45 +96,32 @@ class TalkerHttpLogger extends InterceptorContract { }) async { final String message = '${response.request?.url}'; - try { - switch (response.statusCode) { - case int statusCode when settings.enabled && statusCode < 400: - if (settings.responseFilter?.call(response) ?? true) { - _talker.logCustom( - HttpResponseLog( - message, - response: response, - settings: settings, - ), - ); - } - break; - case _ when settings.enabled: - if (settings.errorFilter?.call(response) ?? true) { - _talker.logCustom( - HttpErrorLog( - message, - request: response.request, - response: response, - settings: settings, - ), - ); - } - break; - } - - return response; - } catch (exception, stackTrace) { - switch (exception) { - case ClientException ex when settings.enabled: - _talker.error(ex.uri.toString(), ex, stackTrace); - break; - case _ when settings.enabled: - _talker.error(exception.toString(), exception, stackTrace); - break; - } - - rethrow; + switch (response.statusCode) { + case int statusCode when settings.enabled && statusCode < 400: + if (settings.responseFilter?.call(response) ?? true) { + _talker.logCustom( + HttpResponseLog( + message, + response: response, + settings: settings, + ), + ); + } + break; + case _ when settings.enabled: + if (settings.errorFilter?.call(response) ?? true) { + _talker.logCustom( + HttpErrorLog( + message, + request: response.request, + response: response, + settings: settings, + ), + ); + } + break; } + + return response; } } From d3fde759eec09e16fbf653b07a191c41a3d9d400 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Mon, 5 May 2025 10:23:44 +0100 Subject: [PATCH 20/30] :technologist: update example --- .../talker_http_logger/example/.gitignore | 46 ++ packages/talker_http_logger/example/.metadata | 36 + packages/talker_http_logger/example/README.md | 16 + .../example/analysis_options.yaml | 11 + .../example/android/.gitignore | 14 + .../example/android/app/build.gradle.kts | 44 ++ .../android/app/src/debug/AndroidManifest.xml | 7 + .../android/app/src/main/AndroidManifest.xml | 45 ++ .../com/example/example/MainActivity.kt | 5 + .../res/drawable-v21/launch_background.xml | 12 + .../main/res/drawable/launch_background.xml | 12 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 544 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 442 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 721 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 1031 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 1443 bytes .../app/src/main/res/values-night/styles.xml | 18 + .../app/src/main/res/values/styles.xml | 18 + .../app/src/profile/AndroidManifest.xml | 7 + .../example/android/build.gradle.kts | 21 + .../example/android/gradle.properties | 3 + .../gradle/wrapper/gradle-wrapper.properties | 5 + .../example/android/settings.gradle.kts | 25 + .../talker_http_logger/example/ios/.gitignore | 36 + .../ios/Flutter/AppFrameworkInfo.plist | 26 + .../example/ios/Flutter/Debug.xcconfig | 2 + .../example/ios/Flutter/Release.xcconfig | 2 + .../talker_http_logger/example/ios/Podfile | 43 ++ .../ios/Runner.xcodeproj/project.pbxproj | 731 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../xcshareddata/xcschemes/Runner.xcscheme | 99 +++ .../contents.xcworkspacedata | 10 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../example/ios/Runner/AppDelegate.swift | 13 + .../AppIcon.appiconset/Contents.json | 122 +++ .../Icon-App-1024x1024@1x.png | Bin 0 -> 10932 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 0 -> 295 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 0 -> 406 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 0 -> 450 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 0 -> 282 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 0 -> 462 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 0 -> 704 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 0 -> 406 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 0 -> 586 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 0 -> 862 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 0 -> 862 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 0 -> 1674 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 0 -> 762 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 0 -> 1226 bytes .../Icon-App-83.5x83.5@2x.png | Bin 0 -> 1418 bytes .../LaunchImage.imageset/Contents.json | 23 + .../LaunchImage.imageset/LaunchImage.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@2x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@3x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/README.md | 5 + .../Runner/Base.lproj/LaunchScreen.storyboard | 37 + .../ios/Runner/Base.lproj/Main.storyboard | 26 + .../example/ios/Runner/Info.plist | 49 ++ .../ios/Runner/Runner-Bridging-Header.h | 1 + .../example/ios/RunnerTests/RunnerTests.swift | 12 + .../talker_http_logger/example/lib/main.dart | 139 ++++ .../talker_http_logger/example/pubspec.yaml | 27 + .../example/talker_http_logger_example.dart | 23 - .../example/web/favicon.png | Bin 0 -> 917 bytes .../example/web/icons/Icon-192.png | Bin 0 -> 5292 bytes .../example/web/icons/Icon-512.png | Bin 0 -> 8252 bytes .../example/web/icons/Icon-maskable-192.png | Bin 0 -> 5594 bytes .../example/web/icons/Icon-maskable-512.png | Bin 0 -> 20998 bytes .../talker_http_logger/example/web/index.html | 38 + .../example/web/manifest.json | 35 + 73 files changed, 1860 insertions(+), 23 deletions(-) create mode 100644 packages/talker_http_logger/example/.gitignore create mode 100644 packages/talker_http_logger/example/.metadata create mode 100644 packages/talker_http_logger/example/README.md create mode 100644 packages/talker_http_logger/example/analysis_options.yaml create mode 100644 packages/talker_http_logger/example/android/.gitignore create mode 100644 packages/talker_http_logger/example/android/app/build.gradle.kts create mode 100644 packages/talker_http_logger/example/android/app/src/debug/AndroidManifest.xml create mode 100644 packages/talker_http_logger/example/android/app/src/main/AndroidManifest.xml create mode 100644 packages/talker_http_logger/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt create mode 100644 packages/talker_http_logger/example/android/app/src/main/res/drawable-v21/launch_background.xml create mode 100644 packages/talker_http_logger/example/android/app/src/main/res/drawable/launch_background.xml create mode 100644 packages/talker_http_logger/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 packages/talker_http_logger/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 packages/talker_http_logger/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 packages/talker_http_logger/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 packages/talker_http_logger/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 packages/talker_http_logger/example/android/app/src/main/res/values-night/styles.xml create mode 100644 packages/talker_http_logger/example/android/app/src/main/res/values/styles.xml create mode 100644 packages/talker_http_logger/example/android/app/src/profile/AndroidManifest.xml create mode 100644 packages/talker_http_logger/example/android/build.gradle.kts create mode 100644 packages/talker_http_logger/example/android/gradle.properties create mode 100644 packages/talker_http_logger/example/android/gradle/wrapper/gradle-wrapper.properties create mode 100644 packages/talker_http_logger/example/android/settings.gradle.kts create mode 100644 packages/talker_http_logger/example/ios/.gitignore create mode 100644 packages/talker_http_logger/example/ios/Flutter/AppFrameworkInfo.plist create mode 100644 packages/talker_http_logger/example/ios/Flutter/Debug.xcconfig create mode 100644 packages/talker_http_logger/example/ios/Flutter/Release.xcconfig create mode 100644 packages/talker_http_logger/example/ios/Podfile create mode 100644 packages/talker_http_logger/example/ios/Runner.xcodeproj/project.pbxproj create mode 100644 packages/talker_http_logger/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 packages/talker_http_logger/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 packages/talker_http_logger/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 packages/talker_http_logger/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme create mode 100644 packages/talker_http_logger/example/ios/Runner.xcworkspace/contents.xcworkspacedata create mode 100644 packages/talker_http_logger/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 packages/talker_http_logger/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 packages/talker_http_logger/example/ios/Runner/AppDelegate.swift create mode 100644 packages/talker_http_logger/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 packages/talker_http_logger/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png create mode 100644 packages/talker_http_logger/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png create mode 100644 packages/talker_http_logger/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png create mode 100644 packages/talker_http_logger/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png create mode 100644 packages/talker_http_logger/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png create mode 100644 packages/talker_http_logger/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png create mode 100644 packages/talker_http_logger/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png create mode 100644 packages/talker_http_logger/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png create mode 100644 packages/talker_http_logger/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png create mode 100644 packages/talker_http_logger/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png create mode 100644 packages/talker_http_logger/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png create mode 100644 packages/talker_http_logger/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png create mode 100644 packages/talker_http_logger/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png create mode 100644 packages/talker_http_logger/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png create mode 100644 packages/talker_http_logger/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png create mode 100644 packages/talker_http_logger/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json create mode 100644 packages/talker_http_logger/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png create mode 100644 packages/talker_http_logger/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png create mode 100644 packages/talker_http_logger/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png create mode 100644 packages/talker_http_logger/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md create mode 100644 packages/talker_http_logger/example/ios/Runner/Base.lproj/LaunchScreen.storyboard create mode 100644 packages/talker_http_logger/example/ios/Runner/Base.lproj/Main.storyboard create mode 100644 packages/talker_http_logger/example/ios/Runner/Info.plist create mode 100644 packages/talker_http_logger/example/ios/Runner/Runner-Bridging-Header.h create mode 100644 packages/talker_http_logger/example/ios/RunnerTests/RunnerTests.swift create mode 100644 packages/talker_http_logger/example/lib/main.dart create mode 100644 packages/talker_http_logger/example/pubspec.yaml delete mode 100644 packages/talker_http_logger/example/talker_http_logger_example.dart create mode 100644 packages/talker_http_logger/example/web/favicon.png create mode 100644 packages/talker_http_logger/example/web/icons/Icon-192.png create mode 100644 packages/talker_http_logger/example/web/icons/Icon-512.png create mode 100644 packages/talker_http_logger/example/web/icons/Icon-maskable-192.png create mode 100644 packages/talker_http_logger/example/web/icons/Icon-maskable-512.png create mode 100644 packages/talker_http_logger/example/web/index.html create mode 100644 packages/talker_http_logger/example/web/manifest.json diff --git a/packages/talker_http_logger/example/.gitignore b/packages/talker_http_logger/example/.gitignore new file mode 100644 index 000000000..3d3d8995a --- /dev/null +++ b/packages/talker_http_logger/example/.gitignore @@ -0,0 +1,46 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.build/ +.buildlog/ +.history +.svn/ +.swiftpm/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.pub-cache/ +.pub/ +/build/ +pubspec.lock + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/packages/talker_http_logger/example/.metadata b/packages/talker_http_logger/example/.metadata new file mode 100644 index 000000000..79f857910 --- /dev/null +++ b/packages/talker_http_logger/example/.metadata @@ -0,0 +1,36 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "ea121f8859e4b13e47a8f845e4586164519588bc" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: ea121f8859e4b13e47a8f845e4586164519588bc + base_revision: ea121f8859e4b13e47a8f845e4586164519588bc + - platform: android + create_revision: ea121f8859e4b13e47a8f845e4586164519588bc + base_revision: ea121f8859e4b13e47a8f845e4586164519588bc + - platform: ios + create_revision: ea121f8859e4b13e47a8f845e4586164519588bc + base_revision: ea121f8859e4b13e47a8f845e4586164519588bc + - platform: web + create_revision: ea121f8859e4b13e47a8f845e4586164519588bc + base_revision: ea121f8859e4b13e47a8f845e4586164519588bc + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/packages/talker_http_logger/example/README.md b/packages/talker_http_logger/example/README.md new file mode 100644 index 000000000..2b3fce4c8 --- /dev/null +++ b/packages/talker_http_logger/example/README.md @@ -0,0 +1,16 @@ +# example + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) + +For help getting started with Flutter development, view the +[online documentation](https://docs.flutter.dev/), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/packages/talker_http_logger/example/analysis_options.yaml b/packages/talker_http_logger/example/analysis_options.yaml new file mode 100644 index 000000000..0bda3e79b --- /dev/null +++ b/packages/talker_http_logger/example/analysis_options.yaml @@ -0,0 +1,11 @@ +analyzer: + exclude: + - "lib/generated_plugin_registrant.dart" + - "**.mocks.dart" + - "**.gen.dart" + +include: package:flutter_lints/flutter.yaml + +linter: + rules: + - require_trailing_commas diff --git a/packages/talker_http_logger/example/android/.gitignore b/packages/talker_http_logger/example/android/.gitignore new file mode 100644 index 000000000..be3943c96 --- /dev/null +++ b/packages/talker_http_logger/example/android/.gitignore @@ -0,0 +1,14 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java +.cxx/ + +# Remember to never publicly share your keystore. +# See https://flutter.dev/to/reference-keystore +key.properties +**/*.keystore +**/*.jks diff --git a/packages/talker_http_logger/example/android/app/build.gradle.kts b/packages/talker_http_logger/example/android/app/build.gradle.kts new file mode 100644 index 000000000..d77dd1aa0 --- /dev/null +++ b/packages/talker_http_logger/example/android/app/build.gradle.kts @@ -0,0 +1,44 @@ +plugins { + id("com.android.application") + id("kotlin-android") + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id("dev.flutter.flutter-gradle-plugin") +} + +android { + namespace = "com.example.example" + compileSdk = flutter.compileSdkVersion + ndkVersion = "27.0.12077973" + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_11.toString() + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId = "com.example.example" + // You can update the following values to match your application needs. + // For more information, see: https://flutter.dev/to/review-gradle-config. + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig = signingConfigs.getByName("debug") + } + } +} + +flutter { + source = "../.." +} diff --git a/packages/talker_http_logger/example/android/app/src/debug/AndroidManifest.xml b/packages/talker_http_logger/example/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 000000000..399f6981d --- /dev/null +++ b/packages/talker_http_logger/example/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/packages/talker_http_logger/example/android/app/src/main/AndroidManifest.xml b/packages/talker_http_logger/example/android/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..74a78b939 --- /dev/null +++ b/packages/talker_http_logger/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/talker_http_logger/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt b/packages/talker_http_logger/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt new file mode 100644 index 000000000..ac81bae64 --- /dev/null +++ b/packages/talker_http_logger/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt @@ -0,0 +1,5 @@ +package com.example.example + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity : FlutterActivity() diff --git a/packages/talker_http_logger/example/android/app/src/main/res/drawable-v21/launch_background.xml b/packages/talker_http_logger/example/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 000000000..f74085f3f --- /dev/null +++ b/packages/talker_http_logger/example/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/packages/talker_http_logger/example/android/app/src/main/res/drawable/launch_background.xml b/packages/talker_http_logger/example/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 000000000..304732f88 --- /dev/null +++ b/packages/talker_http_logger/example/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/packages/talker_http_logger/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/talker_http_logger/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..db77bb4b7b0906d62b1847e87f15cdcacf6a4f29 GIT binary patch literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ literal 0 HcmV?d00001 diff --git a/packages/talker_http_logger/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/packages/talker_http_logger/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..17987b79bb8a35cc66c3c1fd44f5a5526c1b78be GIT binary patch literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xx&nMcT!A!W`0S9QKQy;}1Cl^CgaH=;G9cpY;r$Q>i*pfB zP2drbID<_#qf;rPZx^FqH)F_D#*k@@q03KywUtLX8Ua?`H+NMzkczFPK3lFz@i_kW%1NOn0|D2I9n9wzH8m|-tHjsw|9>@K=iMBhxvkv6m8Y-l zytQ?X=U+MF$@3 zt`~i=@j|6y)RWMK--}M|=T`o&^Ni>IoWKHEbBXz7?A@mgWoL>!*SXo`SZH-*HSdS+ yn*9;$7;m`l>wYBC5bq;=U}IMqLzqbYCidGC!)_gkIk_C@Uy!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R` zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg zoq1^2_p9@|WEo z*X_Uko@K)qYYv~>43eQGMdbiGbo>E~Q& zrYBH{QP^@Sti!`2)uG{irBBq@y*$B zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N zdG@vOZB4v_lF7Plrx+hxo7(fCV&}fHq)$ literal 0 HcmV?d00001 diff --git a/packages/talker_http_logger/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/packages/talker_http_logger/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..d5f1c8d34e7a88e3f88bea192c3a370d44689c3c GIT binary patch literal 1031 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof literal 0 HcmV?d00001 diff --git a/packages/talker_http_logger/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/packages/talker_http_logger/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..4d6372eebdb28e45604e46eeda8dd24651419bc0 GIT binary patch literal 1443 zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`YV6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY zB_MsH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~Lo9vl;Zfs+W#BydUw zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3 z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w! zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%4Q8~Mad z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt* zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW zu72MW`|?8ht^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf< zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$ zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+ zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f z%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP z(1P?z~7YxD~Rf<(a@_y` literal 0 HcmV?d00001 diff --git a/packages/talker_http_logger/example/android/app/src/main/res/values-night/styles.xml b/packages/talker_http_logger/example/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 000000000..06952be74 --- /dev/null +++ b/packages/talker_http_logger/example/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/packages/talker_http_logger/example/android/app/src/main/res/values/styles.xml b/packages/talker_http_logger/example/android/app/src/main/res/values/styles.xml new file mode 100644 index 000000000..cb1ef8805 --- /dev/null +++ b/packages/talker_http_logger/example/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/packages/talker_http_logger/example/android/app/src/profile/AndroidManifest.xml b/packages/talker_http_logger/example/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 000000000..399f6981d --- /dev/null +++ b/packages/talker_http_logger/example/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/packages/talker_http_logger/example/android/build.gradle.kts b/packages/talker_http_logger/example/android/build.gradle.kts new file mode 100644 index 000000000..89176ef44 --- /dev/null +++ b/packages/talker_http_logger/example/android/build.gradle.kts @@ -0,0 +1,21 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get() +rootProject.layout.buildDirectory.value(newBuildDir) + +subprojects { + val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) + project.layout.buildDirectory.value(newSubprojectBuildDir) +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/packages/talker_http_logger/example/android/gradle.properties b/packages/talker_http_logger/example/android/gradle.properties new file mode 100644 index 000000000..f018a6181 --- /dev/null +++ b/packages/talker_http_logger/example/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError +android.useAndroidX=true +android.enableJetifier=true diff --git a/packages/talker_http_logger/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/talker_http_logger/example/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..afa1e8eb0 --- /dev/null +++ b/packages/talker_http_logger/example/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip diff --git a/packages/talker_http_logger/example/android/settings.gradle.kts b/packages/talker_http_logger/example/android/settings.gradle.kts new file mode 100644 index 000000000..a439442c2 --- /dev/null +++ b/packages/talker_http_logger/example/android/settings.gradle.kts @@ -0,0 +1,25 @@ +pluginManagement { + val flutterSdkPath = run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.7.0" apply false + id("org.jetbrains.kotlin.android") version "1.8.22" apply false +} + +include(":app") diff --git a/packages/talker_http_logger/example/ios/.gitignore b/packages/talker_http_logger/example/ios/.gitignore new file mode 100644 index 000000000..993c497d7 --- /dev/null +++ b/packages/talker_http_logger/example/ios/.gitignore @@ -0,0 +1,36 @@ +**/dgph +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/ephemeral/ +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 + +Podfile.lock diff --git a/packages/talker_http_logger/example/ios/Flutter/AppFrameworkInfo.plist b/packages/talker_http_logger/example/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 000000000..7c5696400 --- /dev/null +++ b/packages/talker_http_logger/example/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 12.0 + + diff --git a/packages/talker_http_logger/example/ios/Flutter/Debug.xcconfig b/packages/talker_http_logger/example/ios/Flutter/Debug.xcconfig new file mode 100644 index 000000000..ec97fc6f3 --- /dev/null +++ b/packages/talker_http_logger/example/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/packages/talker_http_logger/example/ios/Flutter/Release.xcconfig b/packages/talker_http_logger/example/ios/Flutter/Release.xcconfig new file mode 100644 index 000000000..c4855bfe2 --- /dev/null +++ b/packages/talker_http_logger/example/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/packages/talker_http_logger/example/ios/Podfile b/packages/talker_http_logger/example/ios/Podfile new file mode 100644 index 000000000..e549ee22f --- /dev/null +++ b/packages/talker_http_logger/example/ios/Podfile @@ -0,0 +1,43 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '12.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/packages/talker_http_logger/example/ios/Runner.xcodeproj/project.pbxproj b/packages/talker_http_logger/example/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 000000000..166d90387 --- /dev/null +++ b/packages/talker_http_logger/example/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,731 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 0349975BD96070230C2ECB21 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EDD2E4EED1632F8AE49946CE /* Pods_Runner.framework */; }; + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 5B8111CFC21719E178446F90 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 57157F71654DDC088CF06FBE /* Pods_RunnerTests.framework */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 57157F71654DDC088CF06FBE /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 58D6CBE4547B3036C6252C06 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + 5F637F1C7C8541B999CB5454 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + 63282D6269B8F68246D76081 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + 73F049D3BB980382AD75683A /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 89B6B8A988902DB1E2E01E1F /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + E2DB985429F6CC0766642994 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + EDD2E4EED1632F8AE49946CE /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 0349975BD96070230C2ECB21 /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FBAE7A6ED3AD0C8F29996905 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5B8111CFC21719E178446F90 /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 590A0B4D6205CA39BE159923 /* Pods */ = { + isa = PBXGroup; + children = ( + E2DB985429F6CC0766642994 /* Pods-Runner.debug.xcconfig */, + 73F049D3BB980382AD75683A /* Pods-Runner.release.xcconfig */, + 89B6B8A988902DB1E2E01E1F /* Pods-Runner.profile.xcconfig */, + 5F637F1C7C8541B999CB5454 /* Pods-RunnerTests.debug.xcconfig */, + 58D6CBE4547B3036C6252C06 /* Pods-RunnerTests.release.xcconfig */, + 63282D6269B8F68246D76081 /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + 6A79C0DF6F3EB005401B55E4 /* Frameworks */ = { + isa = PBXGroup; + children = ( + EDD2E4EED1632F8AE49946CE /* Pods_Runner.framework */, + 57157F71654DDC088CF06FBE /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + 331C8082294A63A400263BE5 /* RunnerTests */, + 590A0B4D6205CA39BE159923 /* Pods */, + 6A79C0DF6F3EB005401B55E4 /* Frameworks */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + F2EBB17EDE09C97A3C31A953 /* [CP] Check Pods Manifest.lock */, + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, + FBAE7A6ED3AD0C8F29996905 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + A93AFDABF02DCF34B8C34490 /* [CP] Check Pods Manifest.lock */, + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + 929F1C8D4C242F96E65A93DF /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + 331C8080294A63A400263BE5 /* RunnerTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 929F1C8D4C242F96E65A93DF /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; + A93AFDABF02DCF34B8C34490 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + F2EBB17EDE09C97A3C31A953 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 6LYC36B94Q; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.example; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5F637F1C7C8541B999CB5454 /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 58D6CBE4547B3036C6252C06 /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 63282D6269B8F68246D76081 /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 6LYC36B94Q; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.example; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 6LYC36B94Q; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.example; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/packages/talker_http_logger/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/talker_http_logger/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/packages/talker_http_logger/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/packages/talker_http_logger/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/talker_http_logger/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/packages/talker_http_logger/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/talker_http_logger/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/talker_http_logger/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000..f9b0d7c5e --- /dev/null +++ b/packages/talker_http_logger/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/packages/talker_http_logger/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/talker_http_logger/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 000000000..15cada483 --- /dev/null +++ b/packages/talker_http_logger/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/talker_http_logger/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/talker_http_logger/example/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..21a3cc14c --- /dev/null +++ b/packages/talker_http_logger/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/packages/talker_http_logger/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/talker_http_logger/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/packages/talker_http_logger/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/talker_http_logger/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/talker_http_logger/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000..f9b0d7c5e --- /dev/null +++ b/packages/talker_http_logger/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/packages/talker_http_logger/example/ios/Runner/AppDelegate.swift b/packages/talker_http_logger/example/ios/Runner/AppDelegate.swift new file mode 100644 index 000000000..626664468 --- /dev/null +++ b/packages/talker_http_logger/example/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import Flutter +import UIKit + +@main +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/packages/talker_http_logger/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/talker_http_logger/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..d36b1fab2 --- /dev/null +++ b/packages/talker_http_logger/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/packages/talker_http_logger/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/packages/talker_http_logger/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..dc9ada4725e9b0ddb1deab583e5b5102493aa332 GIT binary patch literal 10932 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 literal 0 HcmV?d00001 diff --git a/packages/talker_http_logger/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/packages/talker_http_logger/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..797d452e458972bab9d994556c8305db4c827017 GIT binary patch literal 406 zcmV;H0crk;P))>cdjpWt&rLJgVp-t?DREyuq1A%0Z4)6_WsQ7{nzjN zo!X zGXV)2i3kcZIL~_j>uIKPK_zib+3T+Nt3Mb&Br)s)UIaA}@p{wDda>7=Q|mGRp7pqY zkJ!7E{MNz$9nOwoVqpFb)}$IP24Wn2JJ=Cw(!`OXJBr45rP>>AQr$6c7slJWvbpNW z@KTwna6d?PP>hvXCcp=4F;=GR@R4E7{4VU^0p4F>v^#A|>07*qoM6N<$f*5nx ACIA2c literal 0 HcmV?d00001 diff --git a/packages/talker_http_logger/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/talker_http_logger/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..6ed2d933e1120817fe9182483a228007b18ab6ae GIT binary patch literal 450 zcmV;z0X_bSP)iGWQ_5NJQ_~rNh*z)}eT%KUb z`7gNk0#AwF^#0T0?hIa^`~Ck;!}#m+_uT050aTR(J!bU#|IzRL%^UsMS#KsYnTF*!YeDOytlP4VhV?b} z%rz_<=#CPc)tU1MZTq~*2=8~iZ!lSa<{9b@2Jl;?IEV8)=fG217*|@)CCYgFze-x? zIFODUIA>nWKpE+bn~n7;-89sa>#DR>TSlqWk*!2hSN6D~Qb#VqbP~4Fk&m`@1$JGr zXPIdeRE&b2Thd#{MtDK$px*d3-Wx``>!oimf%|A-&-q*6KAH)e$3|6JV%HX{Hig)k suLT-RhftRq8b9;(V=235Wa|I=027H2wCDra;{X5v07*qoM6N<$f;9x^2LJ#7 literal 0 HcmV?d00001 diff --git a/packages/talker_http_logger/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/packages/talker_http_logger/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..4cd7b0099ca80c806f8fe495613e8d6c69460d76 GIT binary patch literal 282 zcmV+#0p(^bcu7P-R4C8Q z&e;xxFbF_Vrezo%_kH*OKhshZ6BFpG-Y1e10`QXJKbND7AMQ&cMj60B5TNObaZxYybcN07*qoM6N<$g3m;S%K!iX literal 0 HcmV?d00001 diff --git a/packages/talker_http_logger/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/talker_http_logger/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..fe730945a01f64a61e2235dbe3f45b08f7729182 GIT binary patch literal 462 zcmV;<0WtoGP)-}iV`2<;=$?g5M=KQbZ{F&YRNy7Nn@%_*5{gvDM0aKI4?ESmw z{NnZg)A0R`+4?NF_RZexyVB&^^ZvN!{I28tr{Vje;QNTz`dG&Jz0~Ek&f2;*Z7>B|cg}xYpxEFY+0YrKLF;^Q+-HreN0P{&i zK~zY`?b7ECf-n?@;d<&orQ*Q7KoR%4|C>{W^h6@&01>0SKS`dn{Q}GT%Qj_{PLZ_& zs`MFI#j-(>?bvdZ!8^xTwlY{qA)T4QLbY@j(!YJ7aXJervHy6HaG_2SB`6CC{He}f zHVw(fJWApwPq!6VY7r1w-Fs)@ox~N+q|w~e;JI~C4Vf^@d>Wvj=fl`^u9x9wd9 zR%3*Q+)t%S!MU_`id^@&Y{y7-r98lZX0?YrHlfmwb?#}^1b{8g&KzmkE(L>Z&)179 zp<)v6Y}pRl100G2FL_t(o!|l{-Q-VMg#&MKg7c{O0 z2wJImOS3Gy*Z2Qifdv~JYOp;v+U)a|nLoc7hNH;I$;lzDt$}rkaFw1mYK5_0Q(Sut zvbEloxON7$+HSOgC9Z8ltuC&0OSF!-mXv5caV>#bc3@hBPX@I$58-z}(ZZE!t-aOG zpjNkbau@>yEzH(5Yj4kZiMH32XI!4~gVXNnjAvRx;Sdg^`>2DpUEwoMhTs_st8pKG z(%SHyHdU&v%f36~uERh!bd`!T2dw;z6PrOTQ7Vt*#9F2uHlUVnb#ev_o^fh}Dzmq} zWtlk35}k=?xj28uO|5>>$yXadTUE@@IPpgH`gJ~Ro4>jd1IF|(+IX>8M4Ps{PNvmI zNj4D+XgN83gPt_Gm}`Ybv{;+&yu-C(Grdiahmo~BjG-l&mWM+{e5M1sm&=xduwgM9 z`8OEh`=F3r`^E{n_;%9weN{cf2%7=VzC@cYj+lg>+3|D|_1C@{hcU(DyQG_BvBWe? zvTv``=%b1zrol#=R`JB)>cdjpWt&rLJgVp-t?DREyuq1A%0Z4)6_WsQ7{nzjN zo!X zGXV)2i3kcZIL~_j>uIKPK_zib+3T+Nt3Mb&Br)s)UIaA}@p{wDda>7=Q|mGRp7pqY zkJ!7E{MNz$9nOwoVqpFb)}$IP24Wn2JJ=Cw(!`OXJBr45rP>>AQr$6c7slJWvbpNW z@KTwna6d?PP>hvXCcp=4F;=GR@R4E7{4VU^0p4F>v^#A|>07*qoM6N<$f*5nx ACIA2c literal 0 HcmV?d00001 diff --git a/packages/talker_http_logger/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/talker_http_logger/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..502f463a9bc882b461c96aadf492d1729e49e725 GIT binary patch literal 586 zcmV-Q0=4~#P)+}#`wDE{8-2Mebf5<{{PqV{TgVcv*r8?UZ3{-|G?_}T*&y;@cqf{ z{Q*~+qr%%p!1pS*_Uicl#q9lc(D`!D`LN62sNwq{oYw(Wmhk)k<@f$!$@ng~_5)Ru z0Z)trIA5^j{DIW^c+vT2%lW+2<(RtE2wR;4O@)Tm`Xr*?A(qYoM}7i5Yxw>D(&6ou zxz!_Xr~yNF+waPe00049Nkl*;a!v6h%{rlvIH#gW3s8p;bFr=l}mRqpW2h zw=OA%hdyL~z+UHOzl0eKhEr$YYOL-c-%Y<)=j?(bzDweB7{b+%_ypvm_cG{SvM=DK zhv{K@m>#Bw>2W$eUI#iU)Wdgs8Y3U+A$Gd&{+j)d)BmGKx+43U_!tik_YlN)>$7G! zhkE!s;%oku3;IwG3U^2kw?z+HM)jB{@zFhK8P#KMSytSthr+4!c(5c%+^UBn`0X*2 zy3(k600_CSZj?O$Qu%&$;|TGUJrptR(HzyIx>5E(2r{eA(<6t3e3I0B)7d6s7?Z5J zZ!rtKvA{MiEBm&KFtoifx>5P^Z=vl)95XJn()aS5%ad(s?4-=Tkis9IGu{`Fy8r+H07*qoM6N<$f20Z)wqMt%V?S?~D#06};F zA3KcL`Wb+>5ObvgQIG&ig8(;V04hz?@cqy3{mSh8o!|U|)cI!1_+!fWH@o*8vh^CU z^ws0;(c$gI+2~q^tO#GDHf@=;DncUw00J^eL_t(&-tE|HQ`%4vfZ;WsBqu-$0nu1R zq^Vj;p$clf^?twn|KHO+IGt^q#a3X?w9dXC@*yxhv&l}F322(8Y1&=P&I}~G@#h6; z1CV9ecD9ZEe87{{NtI*)_aJ<`kJa z?5=RBtFF50s;jQLFil-`)m2wrb=6h(&brpj%nG_U&ut~$?8Rokzxi8zJoWr#2dto5 zOX_URcc<1`Iky+jc;A%Vzx}1QU{2$|cKPom2Vf1{8m`vja4{F>HS?^Nc^rp}xo+Nh zxd}eOm`fm3@MQC1< zIk&aCjb~Yh%5+Yq0`)D;q{#-Uqlv*o+Oor zE!I71Z@ASH3grl8&P^L0WpavHoP|UX4e?!igT`4?AZk$hu*@%6WJ;zDOGlw7kj@ zY5!B-0ft0f?Lgb>C;$Ke07*qoM6N<$f~t1N9smFU literal 0 HcmV?d00001 diff --git a/packages/talker_http_logger/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/talker_http_logger/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..0ec303439225b78712f49115768196d8d76f6790 GIT binary patch literal 862 zcmV-k1EKthP)20Z)wqMt%V?S?~D#06};F zA3KcL`Wb+>5ObvgQIG&ig8(;V04hz?@cqy3{mSh8o!|U|)cI!1_+!fWH@o*8vh^CU z^ws0;(c$gI+2~q^tO#GDHf@=;DncUw00J^eL_t(&-tE|HQ`%4vfZ;WsBqu-$0nu1R zq^Vj;p$clf^?twn|KHO+IGt^q#a3X?w9dXC@*yxhv&l}F322(8Y1&=P&I}~G@#h6; z1CV9ecD9ZEe87{{NtI*)_aJ<`kJa z?5=RBtFF50s;jQLFil-`)m2wrb=6h(&brpj%nG_U&ut~$?8Rokzxi8zJoWr#2dto5 zOX_URcc<1`Iky+jc;A%Vzx}1QU{2$|cKPom2Vf1{8m`vja4{F>HS?^Nc^rp}xo+Nh zxd}eOm`fm3@MQC1< zIk&aCjb~Yh%5+Yq0`)D;q{#-Uqlv*o+Oor zE!I71Z@ASH3grl8&P^L0WpavHoP|UX4e?!igT`4?AZk$hu*@%6WJ;zDOGlw7kj@ zY5!B-0ft0f?Lgb>C;$Ke07*qoM6N<$f~t1N9smFU literal 0 HcmV?d00001 diff --git a/packages/talker_http_logger/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/talker_http_logger/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..e9f5fea27c705180eb716271f41b582e76dcbd90 GIT binary patch literal 1674 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 literal 0 HcmV?d00001 diff --git a/packages/talker_http_logger/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/packages/talker_http_logger/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..0467bf12aa4d28f374bb26596605a46dcbb3e7c8 GIT binary patch literal 1418 zcmV;51$Fv~P)q zKfU)WzW*n(@|xWGCA9ScMt*e9`2kdxPQ&&>|-UCa7_51w+ zLUsW@ZzZSW0y$)Hp~e9%PvP|a03ks1`~K?q{u;6NC8*{AOqIUq{CL&;p56Lf$oQGq z^={4hPQv)y=I|4n+?>7Fim=dxt1 z2H+Dm+1+fh+IF>G0SjJMkQQre1x4|G*Z==(Ot&kCnUrL4I(rf(ucITwmuHf^hXiJT zkdTm&kdTm&kdTm&kdP`esgWG0BcWCVkVZ&2dUwN`cgM8QJb`Z7Z~e<&Yj2(}>Tmf` zm1{eLgw!b{bXkjWbF%dTkTZEJWyWOb##Lfw4EK2}<0d6%>AGS{po>WCOy&f$Tay_> z?NBlkpo@s-O;0V%Y_Xa-G#_O08q5LR*~F%&)}{}r&L%Sbs8AS4t7Y0NEx*{soY=0MZExqA5XHQkqi#4gW3 zqODM^iyZl;dvf)-bOXtOru(s)Uc7~BFx{w-FK;2{`VA?(g&@3z&bfLFyctOH!cVsF z7IL=fo-qBndRUm;kAdXR4e6>k-z|21AaN%ubeVrHl*<|s&Ax@W-t?LR(P-24A5=>a z*R9#QvjzF8n%@1Nw@?CG@6(%>+-0ASK~jEmCV|&a*7-GKT72W<(TbSjf)&Eme6nGE z>Gkj4Sq&2e+-G%|+NM8OOm5zVl9{Z8Dd8A5z3y8mZ=4Bv4%>as_{9cN#bm~;h>62( zdqY93Zy}v&c4n($Vv!UybR8ocs7#zbfX1IY-*w~)p}XyZ-SFC~4w>BvMVr`dFbelV{lLL0bx7@*ZZdebr3`sP;? zVImji)kG)(6Juv0lz@q`F!k1FE;CQ(D0iG$wchPbKZQELlsZ#~rt8#90Y_Xh&3U-< z{s<&cCV_1`^TD^ia9!*mQDq& zn2{r`j};V|uV%_wsP!zB?m%;FeaRe+X47K0e+KE!8C{gAWF8)lCd1u1%~|M!XNRvw zvtqy3iz0WSpWdhn6$hP8PaRBmp)q`#PCA`Vd#Tc$@f1tAcM>f_I@bC)hkI9|o(Iqv zo}Piadq!j76}004RBio<`)70k^`K1NK)q>w?p^C6J2ZC!+UppiK6&y3Kmbv&O!oYF z34$0Z;QO!JOY#!`qyGH<3Pd}Pt@q*A0V=3SVtWKRR8d8Z&@)3qLPA19LPA19LPEUC YUoZo%k(ykuW&i*H07*qoM6N<$f+CH{y8r+H literal 0 HcmV?d00001 diff --git a/packages/talker_http_logger/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/packages/talker_http_logger/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 000000000..0bedcf2fd --- /dev/null +++ b/packages/talker_http_logger/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/packages/talker_http_logger/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/packages/talker_http_logger/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/packages/talker_http_logger/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/packages/talker_http_logger/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/packages/talker_http_logger/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/packages/talker_http_logger/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/packages/talker_http_logger/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/talker_http_logger/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 000000000..89c2725b7 --- /dev/null +++ b/packages/talker_http_logger/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/packages/talker_http_logger/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/talker_http_logger/example/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 000000000..f2e259c7c --- /dev/null +++ b/packages/talker_http_logger/example/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/talker_http_logger/example/ios/Runner/Base.lproj/Main.storyboard b/packages/talker_http_logger/example/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 000000000..f3c28516f --- /dev/null +++ b/packages/talker_http_logger/example/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/talker_http_logger/example/ios/Runner/Info.plist b/packages/talker_http_logger/example/ios/Runner/Info.plist new file mode 100644 index 000000000..5458fc418 --- /dev/null +++ b/packages/talker_http_logger/example/ios/Runner/Info.plist @@ -0,0 +1,49 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Example + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + example + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + + + diff --git a/packages/talker_http_logger/example/ios/Runner/Runner-Bridging-Header.h b/packages/talker_http_logger/example/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 000000000..308a2a560 --- /dev/null +++ b/packages/talker_http_logger/example/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/packages/talker_http_logger/example/ios/RunnerTests/RunnerTests.swift b/packages/talker_http_logger/example/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 000000000..86a7c3b1b --- /dev/null +++ b/packages/talker_http_logger/example/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/packages/talker_http_logger/example/lib/main.dart b/packages/talker_http_logger/example/lib/main.dart new file mode 100644 index 000000000..9f9f7ecee --- /dev/null +++ b/packages/talker_http_logger/example/lib/main.dart @@ -0,0 +1,139 @@ +import 'package:flutter/material.dart'; +import 'package:http_interceptor/http/intercepted_client.dart'; +import 'package:talker_flutter/talker_flutter.dart'; +import 'package:talker_http_logger/talker_http_logger_interceptor.dart'; +import 'package:talker_http_logger/talker_http_logger_settings.dart'; + +void main() { + runApp(MaterialApp(home: const MyApp())); +} + +class MyApp extends StatefulWidget { + const MyApp({super.key}); + + @override + State createState() => _MyAppState(); +} + +class _MyAppState extends State { + final Talker _talker = Talker(); + + late final InterceptedClient client = InterceptedClient.build( + interceptors: [ + TalkerHttpLogger( + talker: _talker, + settings: TalkerHttpLoggerSettings( + printRequestHeaders: true, + printResponseHeaders: true, + hiddenHeaders: {'authorization'}, + ), + ), + ], + ); + + late final List<({String title, VoidCallback onPressed})> _buttons = [ + ( + title: 'GET todo request', + onPressed: () => client.get( + Uri.https("jsonplaceholder.typicode.com", "/todos/1"), + headers: { + "firstHeader": "firstHeaderValue", + "authorization": "bearer super_secret_token", + "lastHeader": "lastHeaderValue", + }, + ), + ), + ( + title: 'GET todos list request', + onPressed: () => + client.get(Uri.https("jsonplaceholder.typicode.com", "/todos")), + ), + ( + title: 'POST todo request', + onPressed: () => client.post( + Uri.https("jsonplaceholder.typicode.com", "/todos"), + body: { + "userId": '1', + "id": '1', + "title": "delectus aut autem", + "completed": 'false', + }, + ), + ), + ( + title: 'PUT todo request', + onPressed: () => client.put( + Uri.https("jsonplaceholder.typicode.com", "/todos/1"), + body: { + "userId": '1', + "id": '1', + "title": "delectus aut autem", + "completed": 'false', + }, + ), + ), + ( + title: 'DELETE todo request', + onPressed: () => + client.delete(Uri.https("jsonplaceholder.typicode.com", "/todos/1")), + ), + ]; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + centerTitle: true, + title: const Text('Talker + Chopper Example'), + backgroundColor: Colors.blue, + foregroundColor: Colors.white, + ), + body: ListView( + padding: const EdgeInsets.symmetric( + vertical: 16, + horizontal: 24, + ), + children: [ + const Text( + 'Check result in console or open Talker Screen', + style: TextStyle(fontSize: 24, fontWeight: FontWeight.w600), + textAlign: TextAlign.center, + ), + const SizedBox(height: 24), + for (final ({String title, VoidCallback onPressed}) button + in _buttons) + Padding( + padding: const EdgeInsets.symmetric(vertical: 4), + child: ElevatedButton( + style: ElevatedButton.styleFrom( + minimumSize: const Size.fromHeight(48), + ), + onPressed: button.onPressed, + child: Text(button.title), + ), + ), + const SizedBox(height: 24), + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Colors.amber, + foregroundColor: Colors.black, + minimumSize: const Size.fromHeight(48), + ), + onPressed: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => TalkerScreen( + talker: _talker, + isLogsExpanded: true, + isLogOrderReversed: true, + ), + ), + ); + }, + child: Text('Go to Talker Screen'), + ), + ], + ), + ); + } +} diff --git a/packages/talker_http_logger/example/pubspec.yaml b/packages/talker_http_logger/example/pubspec.yaml new file mode 100644 index 000000000..0465abf2c --- /dev/null +++ b/packages/talker_http_logger/example/pubspec.yaml @@ -0,0 +1,27 @@ +name: example +description: "Talker + Http Logger Example" +publish_to: 'none' +version: 1.0.0+1 + +environment: + sdk: ^3.0.0 + +dependencies: + flutter: + sdk: flutter + http_interceptor: ^2.0.0 + talker_http_logger: + talker_flutter: + equatable: ^2.0.7 + +dev_dependencies: + flutter_lints: ^5.0.0 + +dependency_overrides: + talker_http_logger: + path: .. + talker_flutter: + path: ../../talker_flutter + +flutter: + uses-material-design: true diff --git a/packages/talker_http_logger/example/talker_http_logger_example.dart b/packages/talker_http_logger/example/talker_http_logger_example.dart deleted file mode 100644 index aa6d6cf0f..000000000 --- a/packages/talker_http_logger/example/talker_http_logger_example.dart +++ /dev/null @@ -1,23 +0,0 @@ -import 'package:http_interceptor/http_interceptor.dart'; -import 'package:talker_http_logger/talker_http_logger.dart'; - -void main(List args) async { - final InterceptedClient client = InterceptedClient.build( - interceptors: [ - TalkerHttpLogger( - settings: TalkerHttpLoggerSettings( - hiddenHeaders: {'Authorization'}, - ), - ), - ], - ); - - await client.get( - Uri.https("google.com"), - headers: { - "firstHeader": "firstHeaderValue", - "authorization": "bearer super_secret_token", - "lastHeader": "lastHeaderValue", - }, - ); -} diff --git a/packages/talker_http_logger/example/web/favicon.png b/packages/talker_http_logger/example/web/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..8aaa46ac1ae21512746f852a42ba87e4165dfdd1 GIT binary patch literal 917 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|I14-?iy0X7 zltGxWVyS%@P(fs7NJL45ua8x7ey(0(N`6wRUPW#JP&EUCO@$SZnVVXYs8ErclUHn2 zVXFjIVFhG^g!Ppaz)DK8ZIvQ?0~DO|i&7O#^-S~(l1AfjnEK zjFOT9D}DX)@^Za$W4-*MbbUihOG|wNBYh(yU7!lx;>x^|#0uTKVr7USFmqf|i<65o z3raHc^AtelCMM;Vme?vOfh>Xph&xL%(-1c06+^uR^q@XSM&D4+Kp$>4P^%3{)XKjo zGZknv$b36P8?Z_gF{nK@`XI}Z90TzwSQO}0J1!f2c(B=V`5aP@1P1a|PZ!4!3&Gl8 zTYqUsf!gYFyJnXpu0!n&N*SYAX-%d(5gVjrHJWqXQshj@!Zm{!01WsQrH~9=kTxW#6SvuapgMqt>$=j#%eyGrQzr zP{L-3gsMA^$I1&gsBAEL+vxi1*Igl=8#8`5?A-T5=z-sk46WA1IUT)AIZHx1rdUrf zVJrJn<74DDw`j)Ki#gt}mIT-Q`XRa2-jQXQoI%w`nb|XblvzK${ZzlV)m-XcwC(od z71_OEC5Bt9GEXosOXaPTYOia#R4ID2TiU~`zVMl08TV_C%DnU4^+HE>9(CE4D6?Fz oujB08i7adh9xk7*FX66dWH6F5TM;?E2b5PlUHx3vIVCg!0Dx9vYXATM literal 0 HcmV?d00001 diff --git a/packages/talker_http_logger/example/web/icons/Icon-192.png b/packages/talker_http_logger/example/web/icons/Icon-192.png new file mode 100644 index 0000000000000000000000000000000000000000..b749bfef07473333cf1dd31e9eed89862a5d52aa GIT binary patch literal 5292 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 literal 0 HcmV?d00001 diff --git a/packages/talker_http_logger/example/web/icons/Icon-512.png b/packages/talker_http_logger/example/web/icons/Icon-512.png new file mode 100644 index 0000000000000000000000000000000000000000..88cfd48dff1169879ba46840804b412fe02fefd6 GIT binary patch literal 8252 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 literal 0 HcmV?d00001 diff --git a/packages/talker_http_logger/example/web/icons/Icon-maskable-192.png b/packages/talker_http_logger/example/web/icons/Icon-maskable-192.png new file mode 100644 index 0000000000000000000000000000000000000000..eb9b4d76e525556d5d89141648c724331630325d GIT binary patch literal 5594 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 X>c!)3PgKfL&lX^$Z>Cpu&6)6jvi^Z! literal 0 HcmV?d00001 diff --git a/packages/talker_http_logger/example/web/icons/Icon-maskable-512.png b/packages/talker_http_logger/example/web/icons/Icon-maskable-512.png new file mode 100644 index 0000000000000000000000000000000000000000..d69c56691fbdb0b7efa65097c7cc1edac12a6d3e GIT binary patch literal 20998 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 MPgg&ebxsLQ025IeI{*Lx literal 0 HcmV?d00001 diff --git a/packages/talker_http_logger/example/web/index.html b/packages/talker_http_logger/example/web/index.html new file mode 100644 index 000000000..29b58086b --- /dev/null +++ b/packages/talker_http_logger/example/web/index.html @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + example + + + + + + diff --git a/packages/talker_http_logger/example/web/manifest.json b/packages/talker_http_logger/example/web/manifest.json new file mode 100644 index 000000000..096edf8fe --- /dev/null +++ b/packages/talker_http_logger/example/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "example", + "short_name": "example", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} From 899932ab19ce76a090da52acd858290bdfb2c7b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Mon, 5 May 2025 10:28:15 +0100 Subject: [PATCH 21/30] :memo: update changelog --- packages/talker_http_logger/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/talker_http_logger/CHANGELOG.md b/packages/talker_http_logger/CHANGELOG.md index 9dcc7cd39..a9000ced2 100644 --- a/packages/talker_http_logger/CHANGELOG.md +++ b/packages/talker_http_logger/CHANGELOG.md @@ -1,3 +1,7 @@ +# 1.0.0 + +- Complete overhaul of the package + # 0.1.0-dev.46 - Update example application dependencies From 9a16d0c8b60c373ff72e1ad2e10c65b6b0f48e4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Mon, 5 May 2025 10:33:16 +0100 Subject: [PATCH 22/30] :art: refactor CurlRequest extension to use static JsonEncoder --- packages/talker_http_logger/lib/curl_request.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/talker_http_logger/lib/curl_request.dart b/packages/talker_http_logger/lib/curl_request.dart index 8f9179194..323055921 100644 --- a/packages/talker_http_logger/lib/curl_request.dart +++ b/packages/talker_http_logger/lib/curl_request.dart @@ -2,9 +2,9 @@ import 'dart:convert' show JsonEncoder, jsonDecode; import 'package:http_interceptor/http_interceptor.dart'; -const JsonEncoder _encoder = JsonEncoder(); - extension CurlRequest on BaseRequest { + static const JsonEncoder _encoder = JsonEncoder(); + /// Converts the request to a curl command string. String toCurl({Map? headers}) { final List curl = ['curl', '-v', '-X', method]; From e2d0b13d8163e2e83596963fb8024c1abb6f1b85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Mon, 5 May 2025 10:48:17 +0100 Subject: [PATCH 23/30] :memo: update README to enhance example project documentation --- packages/talker_dio_logger/example/README.md | 38 ++++++++++++++------ 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/packages/talker_dio_logger/example/README.md b/packages/talker_dio_logger/example/README.md index 2b3fce4c8..237983b2d 100644 --- a/packages/talker_dio_logger/example/README.md +++ b/packages/talker_dio_logger/example/README.md @@ -1,16 +1,34 @@ -# example +# Example Project -A new Flutter project. +This example demonstrates the usage of the talker_http_logger package for logging HTTP requests, responses, and +errors. -## Getting Started +## Setup -This project is a starting point for a Flutter application. +Install dependencies: -A few resources to get you started if this is your first Flutter project: + ```shell + flutter pub get + ``` -- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) +## Running the Example -For help getting started with Flutter development, view the -[online documentation](https://docs.flutter.dev/), which offers tutorials, -samples, guidance on mobile development, and a full API reference. +To run the example application: + + ```shell + flutter run + ``` + +## Directory Structure + +Within the example directory you will typically find: + +- A main entry point that demonstrates the logging functionality. +- Supporting files or configurations that illustrate how logging is customized using the package's settings. + +## Customization + +- Adjust logging settings directly within the example code to explore options such as: + - Printing request headers and data. + - Displaying cURL commands to replicate HTTP requests. + - Customizing the output format of errors, responses, and request logs. From 12c0d1a36e38da1f94c9a88c7b8e19097f4aeaab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Mon, 5 May 2025 10:48:50 +0100 Subject: [PATCH 24/30] :bento: add preview image --- docs/assets/talker_http_logger/preview.png | Bin 0 -> 209292 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/assets/talker_http_logger/preview.png diff --git a/docs/assets/talker_http_logger/preview.png b/docs/assets/talker_http_logger/preview.png new file mode 100644 index 0000000000000000000000000000000000000000..2b57ee3aa5fa066d0378d2f424edd8b486359a03 GIT binary patch literal 209292 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

SQ7NG^ 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 Date: Mon, 5 May 2025 10:57:42 +0100 Subject: [PATCH 25/30] :memo: update readme --- packages/talker_http_logger/README.md | 101 ++++++++++++++++++++++++-- 1 file changed, 93 insertions(+), 8 deletions(-) diff --git a/packages/talker_http_logger/README.md b/packages/talker_http_logger/README.md index a565ee57e..c335dc2bf 100644 --- a/packages/talker_http_logger/README.md +++ b/packages/talker_http_logger/README.md @@ -15,7 +15,7 @@ Lightweight and customizable [http](https://pub.dev/packages/http) client logger ## Preview This is how the logs of your http requests will look in the console -![](https://github.com/Frezyx/talker/blob/dev/docs/assets/talker_http_logger/preview.png?raw=true) +![](/docs/assets/talker_http_logger/preview.png?raw=true) ## Getting started Follow these steps to use this package @@ -23,7 +23,7 @@ Follow these steps to use this package ### Add dependency ```yaml dependencies: - talker_http_logger: ^0.1.0-dev.46 + talker_http_logger: ^1.0.0 ``` ### Usage @@ -35,7 +35,13 @@ import 'package:talker_http_logger/talker_http_logger.dart'; void main() async { final client = InterceptedClient.build(interceptors: [ - TalkerHttpLogger(), + TalkerHttpLogger( + settings: const TalkerHttpLoggerSettings( + printRequestHeaders: true, + printResponseHeaders: true, + printResponseMessage: true, + ), + ), ]); await client.get("https://google.com".toUri()); @@ -52,13 +58,92 @@ import 'package:http_interceptor/http_interceptor.dart'; import 'package:talker_http_logger/talker_http_logger.dart'; void main() async { - final talker = Talker(); - final client = InterceptedClient.build(interceptors: [ - TalkerHttpLogger(talker: talker), - ]); + final _talker = Talker(); + final client = InterceptedClient.build( + /// ... other settings + interceptors: [ + TalkerHttpLogger( + /// ... other Talker HTTP Logger settings + talker: _talker, + ), + ] + ); await client.get("https://google.com".toUri()); -} +``` + +### Print HTTP request curl command + +You can print the curl command for the HTTP request in the console. +This is useful for debugging and testing purposes. + +```dart +final client = InterceptedClient.build( + /// ... other settings + interceptors: [ + TalkerHttpLogger( + talker: _talker, + settings: const TalkerHttpLoggerSettings( + // Print curl command for HTTP request + printRequestCurl: true, + ), + ), + ], +); +``` + +### Hiding sensitive HTTP request headers + +You can hide sensitive HTTP request headers such as `Authorization` or `Cookie` in the console logs. +This is useful for security purposes. + +```dart +final client = InterceptedClient( + /// ... other settings + interceptors: [ + TalkerHttpLogger( + talker: _talker, + settings: const TalkerHttpLoggerSettings( + printRequestHeaders: true, + printResponseHeaders: true, + // Hide sensitive HTTP request headers + hiddenHeaders: { + 'authorization', + 'cookie', + }, + ), + ), + ], +); +``` + +### Change HTTP logs colors + +Customize your HTTP log colors by defining specific colors for requests, responses, and errors in +[TalkerHttpLoggerSettings](lib/talker_http_logger_settings.dart) + +```dart +TalkerHttpLoggerSettings( + // Blue HTTP requests logs in console + requestPen: AnsiPen()..blue(), + // Green HTTP responses logs in console + responsePen: AnsiPen()..green(), + // Error HTTP logs in console + errorPen: AnsiPen()..red(), +); +``` + +### Filter HTTP logs + +For instance, if your app includes private functionality that you prefer not to log with talker, you can apply filters. + +```dart +TalkerHttpLoggerSettings( + // All http request without "/secure" in path will be printed in console + requestFilter: (Request request) => !request.url.path.contains('/secure'), + // All http responses with status codes different than 301 will be printed in console + responseFilter: (Response response) => response.statusCode != 301, +) ``` ## Additional information From 439258f19ba0e676f07b341291bc017a28e10c76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Mon, 5 May 2025 11:09:07 +0100 Subject: [PATCH 26/30] :memo: update readme --- packages/talker_http_logger/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/talker_http_logger/README.md b/packages/talker_http_logger/README.md index c335dc2bf..cf82ccb51 100644 --- a/packages/talker_http_logger/README.md +++ b/packages/talker_http_logger/README.md @@ -1,5 +1,5 @@ # talker_http_logger -Lightweight and customizable [http](https://pub.dev/packages/http) client logger on [talker](https://pub.dev/packages/talker) base.
+Lightweight and customizable [http_interceptor](https://pub.dev/packages/http_interceptor) client logger on [talker](https://pub.dev/packages/talker) base.
[Talker](https://github.com/Frezyx/talker) - Advanced exception handling and logging for dart/flutter applications 🚀

@@ -27,7 +27,7 @@ dependencies: ``` ### Usage -Just add **TalkerHttpLogger** to your **InterceptedClient** instance and it will work +Just add **TalkerHttpLogger** to your [**InterceptedClient**](https://pub.dev/packages/http_interceptor) instance and it will work ```dart import 'package:http_interceptor/http_interceptor.dart'; From dff1d526048032bc36b5014e003f92b2a9900338 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Mon, 5 May 2025 13:31:24 +0100 Subject: [PATCH 27/30] :rewind: revert dio readme change --- packages/talker_dio_logger/example/README.md | 38 ++++++-------------- 1 file changed, 10 insertions(+), 28 deletions(-) diff --git a/packages/talker_dio_logger/example/README.md b/packages/talker_dio_logger/example/README.md index 237983b2d..2b3fce4c8 100644 --- a/packages/talker_dio_logger/example/README.md +++ b/packages/talker_dio_logger/example/README.md @@ -1,34 +1,16 @@ -# Example Project +# example -This example demonstrates the usage of the talker_http_logger package for logging HTTP requests, responses, and -errors. +A new Flutter project. -## Setup +## Getting Started -Install dependencies: +This project is a starting point for a Flutter application. - ```shell - flutter pub get - ``` +A few resources to get you started if this is your first Flutter project: -## Running the Example +- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) -To run the example application: - - ```shell - flutter run - ``` - -## Directory Structure - -Within the example directory you will typically find: - -- A main entry point that demonstrates the logging functionality. -- Supporting files or configurations that illustrate how logging is customized using the package's settings. - -## Customization - -- Adjust logging settings directly within the example code to explore options such as: - - Printing request headers and data. - - Displaying cURL commands to replicate HTTP requests. - - Customizing the output format of errors, responses, and request logs. +For help getting started with Flutter development, view the +[online documentation](https://docs.flutter.dev/), which offers tutorials, +samples, guidance on mobile development, and a full API reference. From 9576e2e5d73a69f1d2fe15ccbf7da797514f1df7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Mon, 5 May 2025 13:32:26 +0100 Subject: [PATCH 28/30] :memo: update example readme --- packages/talker_http_logger/example/README.md | 38 ++++++++++++++----- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/packages/talker_http_logger/example/README.md b/packages/talker_http_logger/example/README.md index 2b3fce4c8..08a48ac8a 100644 --- a/packages/talker_http_logger/example/README.md +++ b/packages/talker_http_logger/example/README.md @@ -1,16 +1,34 @@ -# example +# Example Project -A new Flutter project. +This example demonstrates the usage of the talker_http_logger package for logging HTTP requests, responses, and +errors. -## Getting Started +## Setup -This project is a starting point for a Flutter application. +Install dependencies: -A few resources to get you started if this is your first Flutter project: +```shell +flutter pub get +``` -- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) +## Running the Example -For help getting started with Flutter development, view the -[online documentation](https://docs.flutter.dev/), which offers tutorials, -samples, guidance on mobile development, and a full API reference. +To run the example application: + +```shell +flutter run +``` + +## Directory Structure + +Within the example directory you will typically find: + +- A main entry point that demonstrates the logging functionality. +- Supporting files or configurations that illustrate how logging is customized using the package's settings. + +## Customization + +- Adjust logging settings directly within the example code to explore options such as: + - Printing request headers and data. + - Displaying cURL commands to replicate HTTP requests. + - Customizing the output format of errors, responses, and request logs. From c0015b1c5cd7b88fa6bccb94952b2d5b33fcc21d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Tu=C5=A1ar?= Date: Mon, 5 May 2025 13:34:56 +0100 Subject: [PATCH 29/30] :memo: fix docs --- packages/talker_http_logger/Makefile | 2 +- packages/talker_http_logger/example/lib/main.dart | 2 +- .../talker_http_logger/lib/talker_http_logger_settings.dart | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/talker_http_logger/Makefile b/packages/talker_http_logger/Makefile index 88be5adf5..fc06314a7 100644 --- a/packages/talker_http_logger/Makefile +++ b/packages/talker_http_logger/Makefile @@ -48,7 +48,7 @@ sure: show_test_coverage: @# Help: Run Dart unit tests for the current project and show the coverage. dart pub global activate coverage && dart pub global run coverage:test_with_coverage - lcov --remove coverage/lcov.info '**.g.dart' '**.mock.dart' '**.chopper.dart' -o coverage/lcov_without_generated_code.info --ignore-errors unused + lcov --remove coverage/lcov.info '**.g.dart' '**.mock.dart' -o coverage/lcov_without_generated_code.info --ignore-errors unused genhtml coverage/lcov_without_generated_code.info -o coverage/html source tool/makefile_helpers.sh && open_link "coverage/html/index.html" diff --git a/packages/talker_http_logger/example/lib/main.dart b/packages/talker_http_logger/example/lib/main.dart index 9f9f7ecee..beff9b4f3 100644 --- a/packages/talker_http_logger/example/lib/main.dart +++ b/packages/talker_http_logger/example/lib/main.dart @@ -84,7 +84,7 @@ class _MyAppState extends State { return Scaffold( appBar: AppBar( centerTitle: true, - title: const Text('Talker + Chopper Example'), + title: const Text('Talker + Http Example'), backgroundColor: Colors.blue, foregroundColor: Colors.white, ), diff --git a/packages/talker_http_logger/lib/talker_http_logger_settings.dart b/packages/talker_http_logger/lib/talker_http_logger_settings.dart index 7a02713b4..04ae698d0 100644 --- a/packages/talker_http_logger/lib/talker_http_logger_settings.dart +++ b/packages/talker_http_logger/lib/talker_http_logger_settings.dart @@ -31,7 +31,7 @@ class TalkerHttpLoggerSettings with EquatableMixin { this.errorFilter, }); - /// Print Chopper logger if true + /// Print Http logger if true final bool enabled; // LogLevel, default is debug @@ -112,7 +112,7 @@ class TalkerHttpLoggerSettings with EquatableMixin { final ResponseFilter? responseFilter; /// For error filtering. - /// You can add your custom logic to log only specific Chopper error [Response]. + /// You can add your custom logic to log only specific HTTP error [Response]. final ResponseFilter? errorFilter; /// Header values for the specified keys in the Set will be replaced with *****. From 4835530bee0ec9975e59805dac0ae35d9af66e28 Mon Sep 17 00:00:00 2001 From: Klemen Tusar Date: Mon, 5 May 2025 13:42:07 +0100 Subject: [PATCH 30/30] Update packages/talker_http_logger/README.md Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> --- packages/talker_http_logger/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/talker_http_logger/README.md b/packages/talker_http_logger/README.md index cf82ccb51..e235a2f81 100644 --- a/packages/talker_http_logger/README.md +++ b/packages/talker_http_logger/README.md @@ -139,7 +139,7 @@ For instance, if your app includes private functionality that you prefer not to ```dart TalkerHttpLoggerSettings( - // All http request without "/secure" in path will be printed in console + // All http requests without "/secure" in path will be printed in console requestFilter: (Request request) => !request.url.path.contains('/secure'), // All http responses with status codes different than 301 will be printed in console responseFilter: (Response response) => response.statusCode != 301,

-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