Skip to content

Commit

Permalink
Feat/translation (#206)
Browse files Browse the repository at this point in the history
* feat: added translations implementation

* feat: added translations

* feat: added translations

* feat: added translations

* feat: added translations

* feat: added translations

* feat: added translations

* feat: added translations

* feat: updated translations

* feat: added missing translations

* feat: dart format

* feat: added tests

* feat: fixed default behavior, added tests

* feat: fixes after merge

* feat: updated metadata

* feat: updated metadata
  • Loading branch information
jhomlala authored Jun 28, 2024
1 parent 4dc9928 commit ce2f771
Show file tree
Hide file tree
Showing 28 changed files with 1,037 additions and 223 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
[![pub package](https://img.shields.io/pub/v/alice_chopper.svg)](https://pub.dartlang.org/packages/alice_chopper)
[![pub package](https://img.shields.io/pub/v/alice_http.svg)](https://pub.dartlang.org/packages/alice_http)
[![pub package](https://img.shields.io/pub/v/alice_http_client.svg)](https://pub.dartlang.org/packages/alice_http_client)
[![pub package](https://img.shields.io/pub/v/alice_objectbox.svg)](https://pub.dartlang.org/packages/alice_objectbox)
[![pub package](https://img.shields.io/badge/platform-flutter-blue.svg)](https://github.com/jhomlala/alice)
[![melos](https://img.shields.io/badge/maintained%20with-melos-f700ff.svg?style=flat-square)](https://github.com/invertase/melos)

Expand Down
2 changes: 1 addition & 1 deletion docs/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

```yaml
dependencies:
alice: ^1.0.0-dev7
alice: ^1.0.0-dev8
```
2. Choose adapter based on your HTTP client. **pubspec.yaml** file:
Expand Down
7 changes: 6 additions & 1 deletion packages/alice/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
# 1.0.0-dev-7
# 1.0.0-dev.8
* Added storage abstractions (by Klemen Tusar https://github.com/techouse).
* Added in memory storage implementation (by Klemen Tusar https://github.com/techouse).
* Added translations.

# 1.0.0-dev.7
* Refactored UI code.

# 1.0.0-dev.6
Expand Down
19 changes: 13 additions & 6 deletions packages/alice/lib/core/alice_core.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import 'package:alice/model/alice_http_call.dart';
import 'package:alice/model/alice_http_error.dart';
import 'package:alice/model/alice_http_response.dart';
import 'package:alice/model/alice_log.dart';
import 'package:alice/model/alice_translation.dart';
import 'package:alice/ui/common/alice_context_ext.dart';
import 'package:alice/ui/common/alice_navigation.dart';
import 'package:alice/utils/shake_detector.dart';
import 'package:flutter/material.dart';
Expand Down Expand Up @@ -139,7 +141,6 @@ class AliceCore {
Future<void> _onDidReceiveNotificationResponse(
NotificationResponse response,
) async {
assert(response.payload != null, "payload can't be null");
navigateToCallListScreen();
}

Expand All @@ -165,10 +166,14 @@ class AliceCore {
BuildContext? getContext() => navigatorKey?.currentState?.overlay?.context;

String _getNotificationMessage(AliceStats stats) => <String>[
if (stats.loading > 0) 'Loading: ${stats.loading}',
if (stats.successes > 0) 'Success: ${stats.successes}',
if (stats.redirects > 0) 'Redirect: ${stats.redirects}',
if (stats.errors > 0) 'Error: ${stats.errors}',
if (stats.loading > 0)
'${getContext()?.i18n(AliceTranslationKey.notificationLoading)} ${stats.loading}',
if (stats.successes > 0)
'${getContext()?.i18n(AliceTranslationKey.notificationSuccess)} ${stats.successes}',
if (stats.redirects > 0)
'${getContext()?.i18n(AliceTranslationKey.notificationRedirect)} ${stats.redirects}',
if (stats.errors > 0)
'${getContext()?.i18n(AliceTranslationKey.notificationError)} ${stats.errors}',
].join(' | ');

Future<void> _requestNotificationPermissions() async {
Expand Down Expand Up @@ -207,7 +212,9 @@ class AliceCore {

await _flutterLocalNotificationsPlugin?.show(
0,
'Alice (total: ${stats.total} requests)',
getContext()
?.i18n(AliceTranslationKey.notificationTotalRequests)
.replaceAll("[requestCount]", stats.total.toString()),
message,
_notificationDetails,
payload: '',
Expand Down
356 changes: 356 additions & 0 deletions packages/alice/lib/core/alice_translations.dart

Large diffs are not rendered by default.

122 changes: 72 additions & 50 deletions packages/alice/lib/helper/alice_save_helper.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
// ignore_for_file: use_build_context_synchronously

import 'dart:convert' show JsonEncoder;
import 'dart:io' show Directory, File, FileMode, IOSink, Platform;

import 'package:alice/core/alice_utils.dart';
import 'package:alice/helper/alice_conversion_helper.dart';
import 'package:alice/helper/operating_system.dart';
import 'package:alice/model/alice_http_call.dart';
import 'package:alice/model/alice_translation.dart';
import 'package:alice/ui/common/alice_context_ext.dart';
import 'package:alice/ui/common/alice_dialog.dart';
import 'package:alice/utils/alice_parser.dart';
import 'package:alice/utils/curl.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:open_filex/open_filex.dart';
import 'package:package_info_plus/package_info_plus.dart';
Expand Down Expand Up @@ -61,8 +66,10 @@ class AliceSaveHelper {
} else {
AliceGeneralDialog.show(
context: context,
title: 'Permission error',
description: "Permission not granted. Couldn't save logs.",
title:
context.i18n(AliceTranslationKey.saveDialogPermissionErrorTitle),
description: context
.i18n(AliceTranslationKey.saveDialogPermissionErrorDescription),
);
}
}
Expand All @@ -76,8 +83,9 @@ class AliceSaveHelper {
if (calls.isEmpty) {
AliceGeneralDialog.show(
context: context,
title: 'Error',
description: 'There are no logs to save',
title: context.i18n(AliceTranslationKey.saveDialogEmptyErrorTitle),
description:
context.i18n(AliceTranslationKey.saveDialogEmptyErrorDescription),
);
return '';
}
Expand All @@ -93,19 +101,23 @@ class AliceSaveHelper {
'alice_log_${DateTime.now().millisecondsSinceEpoch}.txt';
final File file = File('${externalDir.path}/$fileName')..createSync();
final IOSink sink = file.openWrite(mode: FileMode.append)
..write(await _buildAliceLog());
..write(await _buildAliceLog(context: context));
for (final AliceHttpCall call in calls) {
sink.write(_buildCallLog(call));
sink.write(_buildCallLog(context: context, call: call));
}
await sink.flush();
await sink.close();

if (context.mounted) {
AliceGeneralDialog.show(
context: context,
title: 'Success',
description: 'Successfully saved logs in ${file.path}',
secondButtonTitle: Platform.isAndroid ? 'View file' : null,
title: context.i18n(AliceTranslationKey.saveSuccessTitle),
description: context
.i18n(AliceTranslationKey.saveSuccessDescription)
.replaceAll("[path]", file.path),
secondButtonTitle: Platform.isAndroid
? context.i18n(AliceTranslationKey.saveSuccessView)
: null,
secondButtonAction: () =>
Platform.isAndroid ? OpenFilex.open(file.path) : null,
);
Expand All @@ -116,17 +128,20 @@ class AliceSaveHelper {
if (context.mounted) {
AliceGeneralDialog.show(
context: context,
title: 'Error',
description: 'Failed to save http calls to file',
title:
context.i18n(AliceTranslationKey.saveDialogFileSaveErrorTitle),
description: context
.i18n(AliceTranslationKey.saveDialogFileSaveErrorDescription),
);
}
}
} catch (exception) {
if (context.mounted) {
AliceGeneralDialog.show(
context: context,
title: 'Error',
description: 'Failed to save http calls to file',
title: context.i18n(AliceTranslationKey.saveDialogFileSaveErrorTitle),
description: context
.i18n(AliceTranslationKey.saveDialogFileSaveErrorDescription),
);
AliceUtils.log(exception.toString());
}
Expand All @@ -135,78 +150,80 @@ class AliceSaveHelper {
return '';
}

static Future<String> _buildAliceLog() async {
static Future<String> _buildAliceLog({required BuildContext context}) async {
final PackageInfo packageInfo = await PackageInfo.fromPlatform();

return 'Alice - HTTP Inspector\n'
'App name: ${packageInfo.appName}\n'
'Package: ${packageInfo.packageName}\n'
'Version: ${packageInfo.version}\n'
'Build number: ${packageInfo.buildNumber}\n'
'Generated: ${DateTime.now().toIso8601String()}\n'
return '${context.i18n(AliceTranslationKey.saveHeaderTitle)}\n'
'${context.i18n(AliceTranslationKey.saveHeaderAppName)} ${packageInfo.appName}\n'
'${context.i18n(AliceTranslationKey.saveHeaderPackage)} ${packageInfo.packageName}\n'
'${context.i18n(AliceTranslationKey.saveHeaderTitle)} ${packageInfo.version}\n'
'${context.i18n(AliceTranslationKey.saveHeaderBuildNumber)} ${packageInfo.buildNumber}\n'
'${context.i18n(AliceTranslationKey.saveHeaderGenerated)} ${DateTime.now().toIso8601String()}\n'
'\n';
}

static String _buildCallLog(AliceHttpCall call) {
static String _buildCallLog(
{required BuildContext context, required AliceHttpCall call}) {
final StringBuffer stringBuffer = StringBuffer()
..writeAll([
'===========================================\n',
'Id: ${call.id}\n',
'${context.i18n(AliceTranslationKey.saveLogId)} ${call.id}\n',
'============================================\n',
'--------------------------------------------\n',
'General data\n',
'${context.i18n(AliceTranslationKey.saveLogGeneralData)}\n',
'--------------------------------------------\n',
'Server: ${call.server} \n',
'Method: ${call.method} \n',
'Endpoint: ${call.endpoint} \n',
'Client: ${call.client} \n',
'Duration ${AliceConversionHelper.formatTime(call.duration)}\n',
'Secured connection: ${call.secure}\n',
'Completed: ${!call.loading} \n',
'${context.i18n(AliceTranslationKey.saveLogServer)} ${call.server} \n',
'${context.i18n(AliceTranslationKey.saveLogMethod)} ${call.method} \n',
'${context.i18n(AliceTranslationKey.saveLogEndpoint)} ${call.endpoint} \n',
'${context.i18n(AliceTranslationKey.saveLogClient)} ${call.client} \n',
'${context.i18n(AliceTranslationKey.saveLogDuration)} ${AliceConversionHelper.formatTime(call.duration)}\n',
'${context.i18n(AliceTranslationKey.saveLogSecured)} ${call.secure}\n',
'${context.i18n(AliceTranslationKey.saveLogCompleted)}: ${!call.loading} \n',
'--------------------------------------------\n',
'Request\n',
'${context.i18n(AliceTranslationKey.saveLogRequest)}\n',
'--------------------------------------------\n',
'Request time: ${call.request?.time}\n',
'Request content type: ${call.request?.contentType}\n',
'Request cookies: ${_encoder.convert(call.request?.cookies)}\n',
'Request headers: ${_encoder.convert(call.request?.headers)}\n',
'${context.i18n(AliceTranslationKey.saveLogRequestTime)} ${call.request?.time}\n',
'${context.i18n(AliceTranslationKey.saveLogRequestContentType)}: ${call.request?.contentType}\n',
'${context.i18n(AliceTranslationKey.saveLogRequestCookies)} ${_encoder.convert(call.request?.cookies)}\n',
'${context.i18n(AliceTranslationKey.saveLogRequestHeaders)} ${_encoder.convert(call.request?.headers)}\n',
]);

if (call.request?.queryParameters.isNotEmpty ?? false) {
stringBuffer.write(
'Request query params: ${_encoder.convert(call.request?.queryParameters)}\n',
'${context.i18n(AliceTranslationKey.saveLogRequestQueryParams)} ${_encoder.convert(call.request?.queryParameters)}\n',
);
}

stringBuffer.writeAll([
'Request size: ${AliceConversionHelper.formatBytes(call.request?.size ?? 0)}\n',
'Request body: ${AliceBodyParser.formatBody(call.request?.body, call.request?.contentType)}\n',
'${context.i18n(AliceTranslationKey.saveLogRequestSize)} ${AliceConversionHelper.formatBytes(call.request?.size ?? 0)}\n',
'${context.i18n(AliceTranslationKey.saveLogRequestBody)} ${AliceBodyParser.formatBody(context: context, body: call.request?.body, contentType: call.request?.contentType)}\n',
'--------------------------------------------\n',
'Response\n',
'${context.i18n(AliceTranslationKey.saveLogResponse)}\n',
'--------------------------------------------\n',
'Response time: ${call.response?.time}\n',
'Response status: ${call.response?.status}\n',
'Response size: ${AliceConversionHelper.formatBytes(call.response?.size ?? 0)}\n',
'Response headers: ${_encoder.convert(call.response?.headers)}\n',
'Response body: ${AliceBodyParser.formatBody(call.response?.body, AliceBodyParser.getContentType(call.response?.headers))}\n',
'${context.i18n(AliceTranslationKey.saveLogResponseTime)} ${call.response?.time}\n',
'${context.i18n(AliceTranslationKey.saveLogResponseStatus)} ${call.response?.status}\n',
'${context.i18n(AliceTranslationKey.saveLogResponseSize)} ${AliceConversionHelper.formatBytes(call.response?.size ?? 0)}\n',
'${context.i18n(AliceTranslationKey.saveLogResponseHeaders)} ${_encoder.convert(call.response?.headers)}\n',
'${context.i18n(AliceTranslationKey.saveLogResponseBody)} ${AliceBodyParser.formatBody(context: context, body: call.response?.body, contentType: AliceBodyParser.getContentType(context: context, headers: call.response?.headers))}\n',
]);

if (call.error != null) {
stringBuffer.writeAll([
'--------------------------------------------\n',
'Error\n',
'${context.i18n(AliceTranslationKey.saveLogError)}\n',
'--------------------------------------------\n',
'Error: ${call.error?.error}\n',
'${context.i18n(AliceTranslationKey.saveLogError)}: ${call.error?.error}\n',
]);

if (call.error?.stackTrace != null) {
stringBuffer.write('Error stacktrace: ${call.error?.stackTrace}\n');
stringBuffer.write(
'${context.i18n(AliceTranslationKey.saveLogStackTrace)}: ${call.error?.stackTrace}\n');
}
}

stringBuffer.writeAll([
'--------------------------------------------\n',
'Curl\n',
'${context.i18n(AliceTranslationKey.saveLogCurl)}\n',
'--------------------------------------------\n',
getCurlCommand(call),
'\n',
Expand All @@ -217,9 +234,14 @@ class AliceSaveHelper {
return stringBuffer.toString();
}

static Future<String> buildCallLog(AliceHttpCall call) async {
static Future<String> buildCallLog(
{required BuildContext context, required AliceHttpCall call}) async {
try {
return await _buildAliceLog() + _buildCallLog(call);
return await _buildAliceLog(context: context) +
_buildCallLog(
call: call,
context: context,
);
} catch (exception) {
return 'Failed to generate call log';
}
Expand Down
Loading

0 comments on commit ce2f771

Please sign in to comment.