├── .fvm
└── fvm_config.json
├── .gitattributes
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── analysis_options.yaml
├── android
├── .gitignore
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
├── settings.gradle
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── kotlin
│ └── com
│ └── cleveroad
│ └── cr_logger
│ └── cr_logger
│ ├── CrLogger.kt
│ └── CrLoggerPlugin.kt
├── assets
├── arrow_down.png
├── content_copy.png
├── ic_back.png
└── ic_menu.png
├── docs
├── .last_build_id
├── assets
│ ├── AssetManifest.bin
│ ├── AssetManifest.bin.json
│ ├── AssetManifest.json
│ ├── FontManifest.json
│ ├── NOTICES
│ ├── assets
│ │ ├── ic_debug.png
│ │ ├── ic_debug_native.png
│ │ ├── ic_error.png
│ │ ├── ic_error_android.png
│ │ ├── ic_error_ios.png
│ │ ├── ic_http.png
│ │ ├── ic_json.png
│ │ ├── ic_warning.png
│ │ ├── ic_warning_android.png
│ │ └── ic_warning_ios.png
│ ├── fonts
│ │ ├── Epilogue-Medium.ttf
│ │ ├── Epilogue-Regular.ttf
│ │ └── MaterialIcons-Regular.otf
│ ├── packages
│ │ ├── cr_logger
│ │ │ ├── assets
│ │ │ │ ├── arrow_down.png
│ │ │ │ ├── content_copy.png
│ │ │ │ ├── ic_back.png
│ │ │ │ └── ic_menu.png
│ │ │ └── fonts
│ │ │ │ ├── Epilogue-Medium.ttf
│ │ │ │ └── Epilogue-Regular.ttf
│ │ └── flutter_dropzone_web
│ │ │ └── assets
│ │ │ └── flutter_dropzone.js
│ └── shaders
│ │ └── ink_sparkle.frag
├── canvaskit
│ ├── canvaskit.js
│ ├── canvaskit.js.symbols
│ ├── canvaskit.wasm
│ ├── chromium
│ │ ├── canvaskit.js
│ │ ├── canvaskit.js.symbols
│ │ └── canvaskit.wasm
│ ├── skwasm.js
│ ├── skwasm.js.symbols
│ ├── skwasm.wasm
│ └── skwasm.worker.js
├── flutter.js
├── flutter_service_worker.js
├── index.html
├── main.dart.js
├── styles.css
└── version.json
├── example
├── .gitignore
├── README.md
├── android
│ ├── .gitignore
│ ├── app
│ │ ├── build.gradle
│ │ └── src
│ │ │ ├── debug
│ │ │ └── AndroidManifest.xml
│ │ │ ├── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── kotlin
│ │ │ │ └── com
│ │ │ │ │ └── cleveroad
│ │ │ │ │ └── cr_logger
│ │ │ │ │ └── cr_logger_example
│ │ │ │ │ └── MainActivity.kt
│ │ │ └── res
│ │ │ │ ├── drawable-v21
│ │ │ │ └── launch_background.xml
│ │ │ │ ├── drawable
│ │ │ │ └── launch_background.xml
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ │ ├── values-night
│ │ │ │ └── styles.xml
│ │ │ │ └── values
│ │ │ │ └── styles.xml
│ │ │ └── profile
│ │ │ └── AndroidManifest.xml
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradle
│ │ └── wrapper
│ │ │ └── gradle-wrapper.properties
│ └── settings.gradle
├── assets
│ ├── ic_debug.png
│ ├── ic_debug_native.png
│ ├── ic_error.png
│ ├── ic_error_android.png
│ ├── ic_error_ios.png
│ ├── ic_http.png
│ ├── ic_json.png
│ ├── ic_warning.png
│ ├── ic_warning_android.png
│ └── ic_warning_ios.png
├── fonts
│ ├── Epilogue-Medium.ttf
│ └── Epilogue-Regular.ttf
├── ios
│ ├── .gitignore
│ ├── Flutter
│ │ ├── AppFrameworkInfo.plist
│ │ ├── Debug.xcconfig
│ │ └── Release.xcconfig
│ ├── Podfile
│ ├── Runner.xcodeproj
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata
│ │ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ │ └── WorkspaceSettings.xcsettings
│ │ └── xcshareddata
│ │ │ └── xcschemes
│ │ │ └── Runner.xcscheme
│ ├── Runner.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── WorkspaceSettings.xcsettings
│ └── Runner
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ ├── Contents.json
│ │ │ ├── Icon-App-1024x1024@1x.png
│ │ │ ├── Icon-App-20x20@1x.png
│ │ │ ├── Icon-App-20x20@2x.png
│ │ │ ├── Icon-App-20x20@3x.png
│ │ │ ├── Icon-App-29x29@1x.png
│ │ │ ├── Icon-App-29x29@2x.png
│ │ │ ├── Icon-App-29x29@3x.png
│ │ │ ├── Icon-App-40x40@1x.png
│ │ │ ├── Icon-App-40x40@2x.png
│ │ │ ├── Icon-App-40x40@3x.png
│ │ │ ├── Icon-App-60x60@2x.png
│ │ │ ├── Icon-App-60x60@3x.png
│ │ │ ├── Icon-App-76x76@1x.png
│ │ │ ├── Icon-App-76x76@2x.png
│ │ │ └── Icon-App-83.5x83.5@2x.png
│ │ └── LaunchImage.imageset
│ │ │ ├── Contents.json
│ │ │ ├── LaunchImage.png
│ │ │ ├── LaunchImage@2x.png
│ │ │ ├── LaunchImage@3x.png
│ │ │ └── README.md
│ │ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ │ ├── Info.plist
│ │ └── Runner-Bridging-Header.h
├── lib
│ ├── generated
│ │ └── assets.dart
│ ├── main.dart
│ ├── rest_client.dart
│ ├── styles.dart
│ ├── utils
│ │ └── try_cast.dart
│ └── widgets
│ │ └── example_btn.dart
├── pubspec.yaml
└── web
│ ├── index.html
│ └── styles.css
├── fonts
├── Epilogue-Medium.ttf
└── Epilogue-Regular.ttf
├── ios
├── .gitignore
├── Assets
│ └── .gitkeep
├── Classes
│ ├── CrLogger.swift
│ ├── CrLoggerPlugin.h
│ ├── CrLoggerPlugin.m
│ └── SwiftCrLoggerPlugin.swift
└── cr_logger.podspec
├── lib
├── cr_logger.dart
├── cr_logger_web.dart
├── generated
│ └── assets.dart
└── src
│ ├── base
│ └── base_page_with_progress.dart
│ ├── constants.dart
│ ├── controllers
│ ├── logs_mode.dart
│ └── logs_mode_controller.dart
│ ├── cr_logger.dart
│ ├── cr_logger_helper.dart
│ ├── cr_logger_wrapper.dart
│ ├── data
│ ├── bean
│ │ ├── error_bean.dart
│ │ ├── http_bean.dart
│ │ ├── log_bean.dart
│ │ ├── request_bean.dart
│ │ └── response_bean.dart
│ ├── models
│ │ └── log_type.dart
│ └── sqflite_db
│ │ ├── converters
│ │ ├── http_enitity_converter.dart
│ │ └── log_entity_converters.dart
│ │ ├── entities
│ │ ├── http_entity.dart
│ │ └── log_entity.dart
│ │ ├── log_module.dart
│ │ └── sqflite_repository.dart
│ ├── dio_log.dart
│ ├── extensions
│ ├── ansi_color_ext.dart
│ ├── card_theme_ext.dart
│ ├── cast.dart
│ ├── date_time.dart
│ ├── do_post_frame.dart
│ ├── extensions.dart
│ ├── image_ext.dart
│ ├── int_ext.dart
│ └── theme_data_ext.dart
│ ├── interceptor
│ ├── chopper_log_interceptor.dart
│ ├── cr_http_adapter.dart
│ ├── cr_http_client_adapter.dart
│ └── dio_log_interceptor.dart
│ ├── js
│ ├── console_output_worker.dart
│ ├── error_worker_scripts.dart
│ ├── http_pretty_output_scripts.dart
│ ├── request_worker_scripts.dart
│ ├── response_worker_scripts.dart
│ └── scripts.dart
│ ├── log_message_wrapper.dart
│ ├── managers
│ ├── http_log_manager.dart
│ ├── log_manager.dart
│ └── transfer_manager.dart
│ ├── models
│ ├── http_log_type.dart
│ └── request_status.dart
│ ├── overlay_draggable_button.dart
│ ├── page
│ ├── actions_and_values
│ │ ├── actions_and_values_page.dart
│ │ ├── actions_manager.dart
│ │ ├── models
│ │ │ ├── action_model.dart
│ │ │ └── notifier_data.dart
│ │ ├── notifiers_manager.dart
│ │ └── widgets
│ │ │ ├── action_item.dart
│ │ │ └── value_notifier_item.dart
│ ├── app_info_page.dart
│ ├── http_logs
│ │ ├── http_log_details_page.dart
│ │ └── http_logs_page.dart
│ ├── log_main
│ │ ├── log_main.dart
│ │ ├── log_main_mobile.dart
│ │ ├── log_main_web.dart
│ │ └── widgets
│ │ │ ├── cr_web_appbar_widget.dart
│ │ │ ├── mobile_header_widget.dart
│ │ │ └── web_header_widget.dart
│ ├── logs
│ │ ├── log_local_detail_page.dart
│ │ └── log_page.dart
│ ├── search
│ │ ├── http_search_page.dart
│ │ ├── log_search_page.dart
│ │ ├── search_page.dart
│ │ └── widgets
│ │ │ └── path_widget.dart
│ └── widgets
│ │ ├── app_info_item.dart
│ │ ├── clear_logs_content_widget.dart
│ │ ├── cupertino_search_field.dart
│ │ ├── http_item.dart
│ │ ├── json_details_widget.dart
│ │ ├── local_log_item.dart
│ │ ├── popup_menu.dart
│ │ └── progress_widget.dart
│ ├── providers
│ └── sqflite_provider.dart
│ ├── res
│ ├── colors.dart
│ ├── styles.dart
│ └── theme.dart
│ ├── utils
│ ├── console_log_output.dart
│ ├── copy_clipboard.dart
│ ├── enum_ext.dart
│ ├── hide_values_in_map.dart
│ ├── html_stub.dart
│ ├── json_utils.dart
│ ├── map_ext.dart
│ ├── nothing_log_filter.dart
│ ├── pair.dart
│ ├── paramas_detector
│ │ ├── parameter_model.dart
│ │ └── params_detector.dart
│ ├── parsers
│ │ ├── isolate_parser.dart
│ │ └── url_parser.dart
│ ├── pretty_cr_logger.dart
│ ├── pretty_cr_printer.dart
│ ├── show_info_dialog.dart
│ ├── show_log_snack_bar.dart
│ ├── show_remove_log_bottom_sheet.dart
│ ├── show_remove_log_snack_bar.dart
│ ├── text_with_params_widget.dart
│ ├── unfocus.dart
│ └── web_utils.dart
│ └── widget
│ ├── adaptive_layout
│ ├── adaptive_layout_widget.dart
│ └── layout_types.dart
│ ├── body_expansion_tile.dart
│ ├── build_number.dart
│ ├── copy_widget.dart
│ ├── cr_app_bar.dart
│ ├── cr_back_button.dart
│ ├── cr_inspector.dart
│ ├── delete_log_confirm_widget.dart
│ ├── error_value_widget.dart
│ ├── expand_arrow_button.dart
│ ├── headers_expansion_tile.dart
│ ├── http_error_widget.dart
│ ├── http_request_widget.dart
│ ├── http_response_widget.dart
│ ├── json_widget
│ ├── json_node_content.dart
│ ├── json_tree_colors.dart
│ └── json_widget.dart
│ ├── options_buttons.dart
│ ├── params_expansion_tile.dart
│ ├── proxy_input_dialog.dart
│ ├── remove_log_widget.dart
│ ├── rounded_card.dart
│ └── url_value_widget.dart
├── pubspec.yaml
├── screenshots
├── debug_log_screenshot.png
├── http-logs-example.gif
├── http_db_log_screenshot.png
├── http_error_screenshot.png
├── http_log_screenshot.png
├── http_request_screenshot.png
├── http_response_screenshot.png
├── http_search_screenshot.png
├── logs_search_screenshot.png
├── plugin_banner.png
├── quick_action_menu_screenshot.png
├── screenshot-web.png
└── settings-screenshot.png
└── test
├── parameter_detector_test.dart
└── replace_curly_braces_test.dart
/.fvm/fvm_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "flutterSdkVersion": "3.16.5",
3 | "flavors": {}
4 | }
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.g.dart -diff
2 | *.svg -diff
3 | *.png -diff
4 | *.lock -diff
5 | *.xcconfig -diff
6 | ios/Runner.xcodeproj/* -diff
7 | ios/Runner.xcworkspace/* -diff
8 | lib/generated/* -diff
9 | ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json -diff
10 | android/app/src/main/res/drawable -diff
11 | *.idea/* -diff
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | *.ipa
7 | *.lock
8 | *.zip
9 | .DS_Store
10 | .atom/
11 | .buildlog/
12 | .history
13 | .svn/
14 |
15 | # IntelliJ related
16 | *.iml
17 | *.ipr
18 | *.iws
19 | .idea/
20 |
21 | # The .vscode folder contains launch configuration and tasks you configure in
22 | # VS Code which you may wish to be included in version control, so this line
23 | # is commented out by default.
24 | #.vscode/
25 |
26 | .gradle
27 | .metadata
28 |
29 | # Flutter/Dart/Pub related
30 | **/doc/api/
31 | .dart_tool/
32 | .flutter-plugins
33 | .flutter-plugins-dependencies
34 | .packages
35 | .pub-cache/
36 | .pub/
37 | .lock/
38 | /build/
39 |
40 | # Web related
41 | lib/generated_plugin_registrant.dart
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2022 Cleveroad
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | group 'com.cleveroad.cr_logger.cr_logger'
2 | version '1.0-SNAPSHOT'
3 |
4 | def localProperties = new Properties()
5 | def localPropertiesFile = rootProject.file('local.properties')
6 | if (localPropertiesFile.exists()) {
7 | localPropertiesFile.withReader('UTF-8') { reader ->
8 | localProperties.load(reader)
9 | }
10 | }
11 |
12 |
13 | buildscript {
14 | ext.kotlin_version = '1.6.10'
15 | repositories {
16 | google()
17 | mavenCentral()
18 | }
19 |
20 | dependencies {
21 | classpath 'com.android.tools.build:gradle:4.2.2'
22 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
23 | }
24 | }
25 |
26 | rootProject.allprojects {
27 | repositories {
28 | google()
29 | mavenCentral()
30 | }
31 | }
32 |
33 | apply plugin: 'com.android.library'
34 | apply plugin: 'kotlin-android'
35 |
36 | android {
37 | compileSdkVersion 30
38 |
39 | compileOptions {
40 | sourceCompatibility JavaVersion.VERSION_1_8
41 | targetCompatibility JavaVersion.VERSION_1_8
42 | }
43 |
44 | kotlinOptions {
45 | jvmTarget = '1.8'
46 | }
47 |
48 | sourceSets {
49 | main.java.srcDirs += 'src/main/kotlin'
50 | }
51 |
52 | defaultConfig {
53 | minSdkVersion 21
54 | }
55 | }
56 |
57 |
58 |
59 | dependencies {
60 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
61 | }
62 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Oct 28 14:44:20 EEST 2021
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'cr_logger'
2 |
3 |
4 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
5 | def properties = new Properties()
6 |
7 | assert localPropertiesFile.exists()
8 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
9 |
10 | def flutterSdkPath = properties.getProperty("flutter.sdk")
11 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
12 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
--------------------------------------------------------------------------------
/android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/android/src/main/kotlin/com/cleveroad/cr_logger/cr_logger/CrLogger.kt:
--------------------------------------------------------------------------------
1 | package com.cleveroad.cr_logger.cr_logger
2 |
3 | import io.flutter.plugin.common.EventChannel
4 |
5 | class CrLogger {
6 | companion object CrLogger {
7 | private const val LOG_TYPE_DEBUG = "d"
8 | private const val LOG_TYPE_INFO = "i"
9 | private const val LOG_TYPE_ERROR = "e"
10 |
11 | private var eventChannel: EventChannel? = null
12 | private var eventSink: EventChannel.EventSink? = null
13 |
14 | fun init(eventChannel: EventChannel) {
15 | this.eventChannel = eventChannel
16 | this.eventChannel?.setStreamHandler(
17 | object : EventChannel.StreamHandler {
18 | override fun onListen(arguments: Any?, events: EventChannel.EventSink) {
19 | eventSink = events
20 |
21 | }
22 |
23 | override fun onCancel(arguments: Any?) {
24 |
25 | }
26 | })
27 |
28 | }
29 |
30 | fun d(message: Any) {
31 | eventSink?.success(listOf(LOG_TYPE_DEBUG, message))
32 | }
33 |
34 | fun i(message: Any) {
35 | eventSink?.success(listOf(LOG_TYPE_INFO, message))
36 | }
37 |
38 | fun e(message: Any) {
39 | eventSink?.success(listOf(LOG_TYPE_ERROR, message))
40 | }
41 | }
42 |
43 | }
--------------------------------------------------------------------------------
/android/src/main/kotlin/com/cleveroad/cr_logger/cr_logger/CrLoggerPlugin.kt:
--------------------------------------------------------------------------------
1 | package com.cleveroad.cr_logger.cr_logger
2 |
3 | import androidx.annotation.NonNull
4 |
5 | import io.flutter.embedding.engine.plugins.FlutterPlugin
6 | import io.flutter.plugin.common.EventChannel
7 | import io.flutter.plugin.common.MethodCall
8 | import io.flutter.plugin.common.MethodChannel
9 | import io.flutter.plugin.common.MethodChannel.MethodCallHandler
10 | import io.flutter.plugin.common.MethodChannel.Result
11 |
12 | /** CrLoggerPlugin */
13 | class CrLoggerPlugin : FlutterPlugin, MethodCallHandler {
14 | /// The MethodChannel that will the communication between Flutter and native Android
15 | ///
16 | /// This local reference serves to register the plugin with the Flutter Engine and unregister it
17 | /// when the Flutter Engine is detached from the Activity
18 | private lateinit var channel: MethodChannel
19 | private lateinit var eventChannel: EventChannel
20 |
21 | override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
22 | channel = MethodChannel(
23 | flutterPluginBinding.binaryMessenger,
24 | "com.cleveroad.cr_logger/method_channel"
25 | )
26 | channel.setMethodCallHandler(this)
27 | eventChannel =
28 | EventChannel(flutterPluginBinding.binaryMessenger, "com.cleveroad.cr_logger/logger")
29 | CrLogger.init(eventChannel)
30 | }
31 |
32 | override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
33 | if (call.method == "getPlatformVersion") {
34 | result.success("Android ${android.os.Build.VERSION.RELEASE}")
35 | } else {
36 | result.notImplemented()
37 | }
38 | }
39 |
40 | override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
41 | channel.setMethodCallHandler(null)
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/assets/arrow_down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/assets/arrow_down.png
--------------------------------------------------------------------------------
/assets/content_copy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/assets/content_copy.png
--------------------------------------------------------------------------------
/assets/ic_back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/assets/ic_back.png
--------------------------------------------------------------------------------
/assets/ic_menu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/assets/ic_menu.png
--------------------------------------------------------------------------------
/docs/.last_build_id:
--------------------------------------------------------------------------------
1 | 846120b4c5c0513ff1e25f1352e8304a
--------------------------------------------------------------------------------
/docs/assets/AssetManifest.bin:
--------------------------------------------------------------------------------
1 |
assets/ic_debug.png
assetassets/ic_debug.pngassets/ic_debug_native.png
assetassets/ic_debug_native.pngassets/ic_error.png
assetassets/ic_error.pngassets/ic_error_android.png
assetassets/ic_error_android.pngassets/ic_error_ios.png
assetassets/ic_error_ios.pngassets/ic_http.png
assetassets/ic_http.pngassets/ic_json.png
assetassets/ic_json.pngassets/ic_warning.png
assetassets/ic_warning.pngassets/ic_warning_android.png
assetassets/ic_warning_android.pngassets/ic_warning_ios.png
assetassets/ic_warning_ios.pngfonts/Epilogue-Medium.ttf
assetfonts/Epilogue-Medium.ttffonts/Epilogue-Regular.ttf
assetfonts/Epilogue-Regular.ttf(packages/cr_logger/assets/arrow_down.png
asset(packages/cr_logger/assets/arrow_down.png*packages/cr_logger/assets/content_copy.png
asset*packages/cr_logger/assets/content_copy.png%packages/cr_logger/assets/ic_back.png
asset%packages/cr_logger/assets/ic_back.png%packages/cr_logger/assets/ic_menu.png
asset%packages/cr_logger/assets/ic_menu.png,packages/cr_logger/fonts/Epilogue-Medium.ttf
asset,packages/cr_logger/fonts/Epilogue-Medium.ttf-packages/cr_logger/fonts/Epilogue-Regular.ttf
asset-packages/cr_logger/fonts/Epilogue-Regular.ttf8packages/flutter_dropzone_web/assets/flutter_dropzone.js
asset8packages/flutter_dropzone_web/assets/flutter_dropzone.js
--------------------------------------------------------------------------------
/docs/assets/AssetManifest.bin.json:
--------------------------------------------------------------------------------
1 | "DRMHE2Fzc2V0cy9pY19kZWJ1Zy5wbmcMAQ0BBwVhc3NldAcTYXNzZXRzL2ljX2RlYnVnLnBuZwcaYXNzZXRzL2ljX2RlYnVnX25hdGl2ZS5wbmcMAQ0BBwVhc3NldAcaYXNzZXRzL2ljX2RlYnVnX25hdGl2ZS5wbmcHE2Fzc2V0cy9pY19lcnJvci5wbmcMAQ0BBwVhc3NldAcTYXNzZXRzL2ljX2Vycm9yLnBuZwcbYXNzZXRzL2ljX2Vycm9yX2FuZHJvaWQucG5nDAENAQcFYXNzZXQHG2Fzc2V0cy9pY19lcnJvcl9hbmRyb2lkLnBuZwcXYXNzZXRzL2ljX2Vycm9yX2lvcy5wbmcMAQ0BBwVhc3NldAcXYXNzZXRzL2ljX2Vycm9yX2lvcy5wbmcHEmFzc2V0cy9pY19odHRwLnBuZwwBDQEHBWFzc2V0BxJhc3NldHMvaWNfaHR0cC5wbmcHEmFzc2V0cy9pY19qc29uLnBuZwwBDQEHBWFzc2V0BxJhc3NldHMvaWNfanNvbi5wbmcHFWFzc2V0cy9pY193YXJuaW5nLnBuZwwBDQEHBWFzc2V0BxVhc3NldHMvaWNfd2FybmluZy5wbmcHHWFzc2V0cy9pY193YXJuaW5nX2FuZHJvaWQucG5nDAENAQcFYXNzZXQHHWFzc2V0cy9pY193YXJuaW5nX2FuZHJvaWQucG5nBxlhc3NldHMvaWNfd2FybmluZ19pb3MucG5nDAENAQcFYXNzZXQHGWFzc2V0cy9pY193YXJuaW5nX2lvcy5wbmcHGWZvbnRzL0VwaWxvZ3VlLU1lZGl1bS50dGYMAQ0BBwVhc3NldAcZZm9udHMvRXBpbG9ndWUtTWVkaXVtLnR0ZgcaZm9udHMvRXBpbG9ndWUtUmVndWxhci50dGYMAQ0BBwVhc3NldAcaZm9udHMvRXBpbG9ndWUtUmVndWxhci50dGYHKHBhY2thZ2VzL2NyX2xvZ2dlci9hc3NldHMvYXJyb3dfZG93bi5wbmcMAQ0BBwVhc3NldAcocGFja2FnZXMvY3JfbG9nZ2VyL2Fzc2V0cy9hcnJvd19kb3duLnBuZwcqcGFja2FnZXMvY3JfbG9nZ2VyL2Fzc2V0cy9jb250ZW50X2NvcHkucG5nDAENAQcFYXNzZXQHKnBhY2thZ2VzL2NyX2xvZ2dlci9hc3NldHMvY29udGVudF9jb3B5LnBuZwclcGFja2FnZXMvY3JfbG9nZ2VyL2Fzc2V0cy9pY19iYWNrLnBuZwwBDQEHBWFzc2V0ByVwYWNrYWdlcy9jcl9sb2dnZXIvYXNzZXRzL2ljX2JhY2sucG5nByVwYWNrYWdlcy9jcl9sb2dnZXIvYXNzZXRzL2ljX21lbnUucG5nDAENAQcFYXNzZXQHJXBhY2thZ2VzL2NyX2xvZ2dlci9hc3NldHMvaWNfbWVudS5wbmcHLHBhY2thZ2VzL2NyX2xvZ2dlci9mb250cy9FcGlsb2d1ZS1NZWRpdW0udHRmDAENAQcFYXNzZXQHLHBhY2thZ2VzL2NyX2xvZ2dlci9mb250cy9FcGlsb2d1ZS1NZWRpdW0udHRmBy1wYWNrYWdlcy9jcl9sb2dnZXIvZm9udHMvRXBpbG9ndWUtUmVndWxhci50dGYMAQ0BBwVhc3NldActcGFja2FnZXMvY3JfbG9nZ2VyL2ZvbnRzL0VwaWxvZ3VlLVJlZ3VsYXIudHRmBzhwYWNrYWdlcy9mbHV0dGVyX2Ryb3B6b25lX3dlYi9hc3NldHMvZmx1dHRlcl9kcm9wem9uZS5qcwwBDQEHBWFzc2V0BzhwYWNrYWdlcy9mbHV0dGVyX2Ryb3B6b25lX3dlYi9hc3NldHMvZmx1dHRlcl9kcm9wem9uZS5qcw=="
--------------------------------------------------------------------------------
/docs/assets/AssetManifest.json:
--------------------------------------------------------------------------------
1 | {"assets/ic_debug.png":["assets/ic_debug.png"],"assets/ic_debug_native.png":["assets/ic_debug_native.png"],"assets/ic_error.png":["assets/ic_error.png"],"assets/ic_error_android.png":["assets/ic_error_android.png"],"assets/ic_error_ios.png":["assets/ic_error_ios.png"],"assets/ic_http.png":["assets/ic_http.png"],"assets/ic_json.png":["assets/ic_json.png"],"assets/ic_warning.png":["assets/ic_warning.png"],"assets/ic_warning_android.png":["assets/ic_warning_android.png"],"assets/ic_warning_ios.png":["assets/ic_warning_ios.png"],"fonts/Epilogue-Medium.ttf":["fonts/Epilogue-Medium.ttf"],"fonts/Epilogue-Regular.ttf":["fonts/Epilogue-Regular.ttf"],"packages/cr_logger/assets/arrow_down.png":["packages/cr_logger/assets/arrow_down.png"],"packages/cr_logger/assets/content_copy.png":["packages/cr_logger/assets/content_copy.png"],"packages/cr_logger/assets/ic_back.png":["packages/cr_logger/assets/ic_back.png"],"packages/cr_logger/assets/ic_menu.png":["packages/cr_logger/assets/ic_menu.png"],"packages/cr_logger/fonts/Epilogue-Medium.ttf":["packages/cr_logger/fonts/Epilogue-Medium.ttf"],"packages/cr_logger/fonts/Epilogue-Regular.ttf":["packages/cr_logger/fonts/Epilogue-Regular.ttf"],"packages/flutter_dropzone_web/assets/flutter_dropzone.js":["packages/flutter_dropzone_web/assets/flutter_dropzone.js"]}
--------------------------------------------------------------------------------
/docs/assets/FontManifest.json:
--------------------------------------------------------------------------------
1 | [{"family":"MaterialIcons","fonts":[{"asset":"fonts/MaterialIcons-Regular.otf"}]},{"family":"Epilogue","fonts":[{"asset":"fonts/Epilogue-Medium.ttf"},{"asset":"fonts/Epilogue-Regular.ttf"}]},{"family":"packages/cr_logger/Epilogue","fonts":[{"asset":"packages/cr_logger/fonts/Epilogue-Medium.ttf"},{"asset":"packages/cr_logger/fonts/Epilogue-Regular.ttf"}]}]
--------------------------------------------------------------------------------
/docs/assets/assets/ic_debug.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/docs/assets/assets/ic_debug.png
--------------------------------------------------------------------------------
/docs/assets/assets/ic_debug_native.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/docs/assets/assets/ic_debug_native.png
--------------------------------------------------------------------------------
/docs/assets/assets/ic_error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/docs/assets/assets/ic_error.png
--------------------------------------------------------------------------------
/docs/assets/assets/ic_error_android.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/docs/assets/assets/ic_error_android.png
--------------------------------------------------------------------------------
/docs/assets/assets/ic_error_ios.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/docs/assets/assets/ic_error_ios.png
--------------------------------------------------------------------------------
/docs/assets/assets/ic_http.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/docs/assets/assets/ic_http.png
--------------------------------------------------------------------------------
/docs/assets/assets/ic_json.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/docs/assets/assets/ic_json.png
--------------------------------------------------------------------------------
/docs/assets/assets/ic_warning.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/docs/assets/assets/ic_warning.png
--------------------------------------------------------------------------------
/docs/assets/assets/ic_warning_android.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/docs/assets/assets/ic_warning_android.png
--------------------------------------------------------------------------------
/docs/assets/assets/ic_warning_ios.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/docs/assets/assets/ic_warning_ios.png
--------------------------------------------------------------------------------
/docs/assets/fonts/Epilogue-Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/docs/assets/fonts/Epilogue-Medium.ttf
--------------------------------------------------------------------------------
/docs/assets/fonts/Epilogue-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/docs/assets/fonts/Epilogue-Regular.ttf
--------------------------------------------------------------------------------
/docs/assets/fonts/MaterialIcons-Regular.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/docs/assets/fonts/MaterialIcons-Regular.otf
--------------------------------------------------------------------------------
/docs/assets/packages/cr_logger/assets/arrow_down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/docs/assets/packages/cr_logger/assets/arrow_down.png
--------------------------------------------------------------------------------
/docs/assets/packages/cr_logger/assets/content_copy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/docs/assets/packages/cr_logger/assets/content_copy.png
--------------------------------------------------------------------------------
/docs/assets/packages/cr_logger/assets/ic_back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/docs/assets/packages/cr_logger/assets/ic_back.png
--------------------------------------------------------------------------------
/docs/assets/packages/cr_logger/assets/ic_menu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/docs/assets/packages/cr_logger/assets/ic_menu.png
--------------------------------------------------------------------------------
/docs/assets/packages/cr_logger/fonts/Epilogue-Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/docs/assets/packages/cr_logger/fonts/Epilogue-Medium.ttf
--------------------------------------------------------------------------------
/docs/assets/packages/cr_logger/fonts/Epilogue-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/docs/assets/packages/cr_logger/fonts/Epilogue-Regular.ttf
--------------------------------------------------------------------------------
/docs/canvaskit/canvaskit.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/docs/canvaskit/canvaskit.wasm
--------------------------------------------------------------------------------
/docs/canvaskit/chromium/canvaskit.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/docs/canvaskit/chromium/canvaskit.wasm
--------------------------------------------------------------------------------
/docs/canvaskit/skwasm.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/docs/canvaskit/skwasm.wasm
--------------------------------------------------------------------------------
/docs/canvaskit/skwasm.worker.js:
--------------------------------------------------------------------------------
1 | "use strict";var Module={};var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";if(ENVIRONMENT_IS_NODE){var nodeWorkerThreads=require("worker_threads");var parentPort=nodeWorkerThreads.parentPort;parentPort.on("message",data=>onmessage({data:data}));var fs=require("fs");Object.assign(global,{self:global,require:require,Module:Module,location:{href:__filename},Worker:nodeWorkerThreads.Worker,importScripts:f=>(0,eval)(fs.readFileSync(f,"utf8")+"//# sourceURL="+f),postMessage:msg=>parentPort.postMessage(msg),performance:global.performance||{now:Date.now}})}var initializedJS=false;function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");if(ENVIRONMENT_IS_NODE){fs.writeSync(2,text+"\n");return}console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=(info,receiveInstance)=>{var module=Module["wasmModule"];Module["wasmModule"]=null;var instance=new WebAssembly.Instance(module,info);return receiveInstance(instance)};self.onunhandledrejection=e=>{throw e.reason??e};function handleMessage(e){try{if(e.data.cmd==="load"){let messageQueue=[];self.onmessage=e=>messageQueue.push(e);self.startWorker=instance=>{Module=instance;postMessage({"cmd":"loaded"});for(let msg of messageQueue){handleMessage(msg)}self.onmessage=handleMessage};Module["wasmModule"]=e.data.wasmModule;for(const handler of e.data.handlers){Module[handler]=(...args)=>{postMessage({cmd:"callHandler",handler:handler,args:args})}}Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;if(typeof e.data.urlOrBlob=="string"){importScripts(e.data.urlOrBlob)}else{var objectUrl=URL.createObjectURL(e.data.urlOrBlob);importScripts(objectUrl);URL.revokeObjectURL(objectUrl)}skwasm(Module)}else if(e.data.cmd==="run"){Module["__emscripten_thread_init"](e.data.pthread_ptr,/*isMainBrowserThread=*/0,/*isMainRuntimeThread=*/0,/*canBlock=*/1);Module["__emscripten_thread_mailbox_await"](e.data.pthread_ptr);Module["establishStackSpace"]();Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInitTLS();if(!initializedJS){initializedJS=true}try{Module["invokeEntryPoint"](e.data.start_routine,e.data.arg)}catch(ex){if(ex!="unwind"){throw ex}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["__emscripten_thread_exit"](-1)}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="checkMailbox"){if(initializedJS){Module["checkMailbox"]()}}else if(e.data.cmd){err("worker.js received unknown command "+e.data.cmd);err(e.data)}}catch(ex){if(Module["__emscripten_thread_crashed"]){Module["__emscripten_thread_crashed"]()}throw ex}}self.onmessage=handleMessage;
2 |
--------------------------------------------------------------------------------
/docs/styles.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/docs/styles.css
--------------------------------------------------------------------------------
/docs/version.json:
--------------------------------------------------------------------------------
1 | {"app_name":"cr_logger_example","version":"1.0.0","build_number":"1","package_name":"cr_logger_example"}
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | **/ios/Flutter/.last_build_id
26 | .dart_tool/
27 | .flutter-plugins
28 | .flutter-plugins-dependencies
29 | .packages
30 | .pub-cache/
31 | .pub/
32 | /build/
33 |
34 | # Web related
35 |
36 | # Symbolication related
37 | app.*.symbols
38 |
39 | # Obfuscation related
40 | app.*.map.json
41 |
42 | # Android Studio will place build artifacts here
43 | /android/app/debug
44 | /android/app/profile
45 | /android/app/release
46 |
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 | # cr_logger_example
2 |
3 | Demonstrates how to use the cr_logger plugin.
4 |
5 | ## Getting Started
6 |
7 | This project is a starting point for a Flutter application.
8 |
9 | A few resources to get you started if this is your first Flutter project:
10 |
11 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab)
12 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook)
13 |
14 | For help getting started with Flutter, view our
15 | [online documentation](https://flutter.dev/docs), which offers tutorials,
16 | samples, guidance on mobile development, and a full API reference.
17 |
--------------------------------------------------------------------------------
/example/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
9 | # Remember to never publicly share your keystore.
10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
11 | key.properties
12 | **/*.keystore
13 | **/*.jks
14 |
--------------------------------------------------------------------------------
/example/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply plugin: 'kotlin-android'
26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
27 |
28 | android {
29 | compileSdkVersion 33
30 |
31 | compileOptions {
32 | sourceCompatibility JavaVersion.VERSION_1_8
33 | targetCompatibility JavaVersion.VERSION_1_8
34 | }
35 |
36 | kotlinOptions {
37 | jvmTarget = '1.8'
38 | }
39 |
40 | sourceSets {
41 | main.java.srcDirs += 'src/main/kotlin'
42 | }
43 |
44 | defaultConfig {
45 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
46 | applicationId "com.cleveroad.cr_logger.cr_logger_example"
47 | minSdkVersion 26
48 | targetSdkVersion 30
49 | versionCode flutterVersionCode.toInteger()
50 | versionName flutterVersionName
51 | }
52 |
53 | buildTypes {
54 | release {
55 | // TODO: Add your own signing config for the release build.
56 | // Signing with the debug keys for now, so `flutter run --release` works.
57 | signingConfig signingConfigs.debug
58 | }
59 | }
60 | }
61 |
62 | flutter {
63 | source '../..'
64 | }
65 |
66 | dependencies {
67 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
68 | }
69 |
--------------------------------------------------------------------------------
/example/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
9 |
16 |
20 |
23 |
28 |
31 |
32 |
33 |
34 |
35 |
36 |
38 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/example/android/app/src/main/kotlin/com/cleveroad/cr_logger/cr_logger_example/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.cleveroad.cr_logger.cr_logger_example
2 |
3 | import androidx.annotation.NonNull
4 | import com.cleveroad.cr_logger.cr_logger.CrLogger
5 | import io.flutter.embedding.android.FlutterActivity
6 | import io.flutter.embedding.engine.FlutterEngine
7 | import io.flutter.plugin.common.MethodChannel
8 |
9 | class MainActivity : FlutterActivity() {
10 | private val CHANNEL = "com.cleveroad.cr_logger_example/logs"
11 |
12 | override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
13 | super.configureFlutterEngine(flutterEngine)
14 | MethodChannel(
15 | flutterEngine.dartExecutor.binaryMessenger,
16 | CHANNEL
17 | ).setMethodCallHandler { call, result ->
18 | when (call.method) {
19 | "debug" -> {
20 | CrLogger.d("Debug logs from native android")
21 | result.success(true)
22 | }
23 | "info" -> {
24 | CrLogger.i("Info logs from native android")
25 | result.success(true)
26 | }
27 | "error" -> {
28 | CrLogger.e("Error logs from native android")
29 | result.success(true)
30 | }
31 | "logJson" -> {
32 | val map = getOrderedMap()
33 | CrLogger.d(map)
34 | CrLogger.i(map)
35 | CrLogger.e(map)
36 | result.success(true)
37 | }
38 | }
39 | }
40 | }
41 |
42 | private fun getOrderedMap(): Map {
43 | val sessionMap = mapOf(
44 | "accessToken" to "gnrjknsmdkom232",
45 | "refreshToken" to "sdapasldofkds123",
46 | "tokenLifetime" to 123456789,
47 | )
48 | val avatarMap = mapOf(
49 | "avatarUrl" to "https://image.example/userId/avatar.jpg",
50 | "smallAvatarUrl" to "https://image.example/userId/small_avatar.jpg",
51 | )
52 |
53 | return mapOf(
54 | "id" to "mnjtnnjw542",
55 | "firstName" to "Steave",
56 | "lastName" to "Jobs",
57 | "session" to sessionMap,
58 | "avatar" to avatarMap,
59 | )
60 | }
61 | }
62 |
63 |
64 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/example/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.9.22'
3 | repositories {
4 | google()
5 | mavenCentral()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:7.4.2'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | }
12 | }
13 |
14 | allprojects {
15 | repositories {
16 | google()
17 | mavenCentral()
18 | }
19 | }
20 |
21 | rootProject.buildDir = '../build'
22 | subprojects {
23 | project.buildDir = "${rootProject.buildDir}/${project.name}"
24 | project.evaluationDependsOn(':app')
25 | }
26 |
27 | tasks.register("clean", Delete) {
28 | delete rootProject.buildDir
29 | }
30 |
--------------------------------------------------------------------------------
/example/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 |
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Oct 26 10:47:45 EEST 2021
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/example/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
4 | def properties = new Properties()
5 |
6 | assert localPropertiesFile.exists()
7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
8 |
9 | def flutterSdkPath = properties.getProperty("flutter.sdk")
10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
12 |
--------------------------------------------------------------------------------
/example/assets/ic_debug.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/example/assets/ic_debug.png
--------------------------------------------------------------------------------
/example/assets/ic_debug_native.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/example/assets/ic_debug_native.png
--------------------------------------------------------------------------------
/example/assets/ic_error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/example/assets/ic_error.png
--------------------------------------------------------------------------------
/example/assets/ic_error_android.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/example/assets/ic_error_android.png
--------------------------------------------------------------------------------
/example/assets/ic_error_ios.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/example/assets/ic_error_ios.png
--------------------------------------------------------------------------------
/example/assets/ic_http.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/example/assets/ic_http.png
--------------------------------------------------------------------------------
/example/assets/ic_json.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/example/assets/ic_json.png
--------------------------------------------------------------------------------
/example/assets/ic_warning.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/example/assets/ic_warning.png
--------------------------------------------------------------------------------
/example/assets/ic_warning_android.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/example/assets/ic_warning_android.png
--------------------------------------------------------------------------------
/example/assets/ic_warning_ios.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/example/assets/ic_warning_ios.png
--------------------------------------------------------------------------------
/example/fonts/Epilogue-Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/example/fonts/Epilogue-Medium.ttf
--------------------------------------------------------------------------------
/example/fonts/Epilogue-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/example/fonts/Epilogue-Regular.ttf
--------------------------------------------------------------------------------
/example/ios/.gitignore:
--------------------------------------------------------------------------------
1 | *.mode1v3
2 | *.mode2v3
3 | *.moved-aside
4 | *.pbxuser
5 | *.perspectivev3
6 | **/*sync/
7 | .sconsign.dblite
8 | .tags*
9 | **/.vagrant/
10 | **/DerivedData/
11 | Icon?
12 | **/Pods/
13 | **/.symlinks/
14 | profile
15 | xcuserdata
16 | **/.generated/
17 | Flutter/App.framework
18 | Flutter/Flutter.framework
19 | Flutter/Flutter.podspec
20 | Flutter/Generated.xcconfig
21 | Flutter/ephemeral/
22 | Flutter/app.flx
23 | Flutter/app.zip
24 | Flutter/flutter_assets/
25 | Flutter/flutter_export_environment.sh
26 | ServiceDefinitions.json
27 | Runner/GeneratedPluginRegistrant.*
28 |
29 | # Exceptions to above rules.
30 | !default.mode1v3
31 | !default.mode2v3
32 | !default.pbxuser
33 | !default.perspectivev3
34 |
--------------------------------------------------------------------------------
/example/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 11.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/example/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/example/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/example/ios/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | # platform :ios, '11.0'
3 |
4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
6 |
7 | project 'Runner', {
8 | 'Debug' => :debug,
9 | 'Profile' => :release,
10 | 'Release' => :release,
11 | }
12 |
13 | def flutter_root
14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
15 | unless File.exist?(generated_xcode_build_settings_path)
16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
17 | end
18 |
19 | File.foreach(generated_xcode_build_settings_path) do |line|
20 | matches = line.match(/FLUTTER_ROOT\=(.*)/)
21 | return matches[1].strip if matches
22 | end
23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
24 | end
25 |
26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
27 |
28 | flutter_ios_podfile_setup
29 |
30 | target 'Runner' do
31 | use_frameworks!
32 | use_modular_headers!
33 |
34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
35 | end
36 |
37 | post_install do |installer|
38 | installer.pods_project.targets.each do |target|
39 | flutter_additional_ios_build_settings(target)
40 | end
41 | end
42 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 | import cr_logger
4 |
5 | let CHANNEL = "com.cleveroad.cr_logger_example/logs"
6 |
7 | @UIApplicationMain
8 | @objc class AppDelegate: FlutterAppDelegate {
9 |
10 |
11 | override func application(
12 | _ application: UIApplication,
13 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
14 | ) -> Bool {
15 | GeneratedPluginRegistrant.register(with: self)
16 |
17 | let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
18 | let loggerChannel = FlutterMethodChannel(name: CHANNEL, binaryMessenger: controller.binaryMessenger)
19 |
20 | loggerChannel.setMethodCallHandler {(call: FlutterMethodCall, result: FlutterResult) -> Void in
21 | switch call.method {
22 | case "debug":
23 | CrLogger.d(message: "Debug logs from native iOS")
24 | case "info":
25 | CrLogger.i(message: "Info logs from native iOS")
26 | break
27 | case "error":
28 | CrLogger.e(message: "Error logs from native iOS")
29 | break
30 | case "logJson":
31 | let keyValuePairsData = self.getOrderedMap()
32 | CrLogger.d(message: keyValuePairsData)
33 | CrLogger.i(message: keyValuePairsData)
34 | CrLogger.e(message: keyValuePairsData)
35 |
36 | default:
37 | result(FlutterMethodNotImplemented)
38 | }
39 | result(true)
40 | }
41 |
42 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
43 | }
44 |
45 |
46 |
47 | private func getOrderedMap() -> KeyValuePairs {
48 | let keyValueSession: KeyValuePairs = [
49 | "accessToken": "gnrjknsmdkom232",
50 | "refreshToken": "sdapasldofkds123",
51 | "tokenLifetime": 123456789
52 | ]
53 |
54 | let keyValueAvatar : KeyValuePairs = [
55 | "avatarUrl": "https://image.example/userId/avatar.jpg",
56 | "smallAvatarUrl":"https://image.example/userId/small_avatar.jpg"
57 | ]
58 |
59 | let keyValueUser : KeyValuePairs = [
60 | "id" : "mnjtnnjw542",
61 | "firstName": "Steave",
62 | "lastName": "Jobs",
63 | "session": keyValueSession,
64 | "avatar": keyValueAvatar,
65 | ]
66 |
67 |
68 | return keyValueUser
69 | }
70 | }
71 |
72 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | 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.
--------------------------------------------------------------------------------
/example/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/example/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/example/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | cr_logger_example
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | $(FLUTTER_BUILD_NAME)
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(FLUTTER_BUILD_NUMBER)
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UISupportedInterfaceOrientations
30 |
31 | UIInterfaceOrientationPortrait
32 | UIInterfaceOrientationLandscapeLeft
33 | UIInterfaceOrientationLandscapeRight
34 |
35 | UISupportedInterfaceOrientations~ipad
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationPortraitUpsideDown
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UIViewControllerBasedStatusBarAppearance
43 |
44 | CADisableMinimumFrameDurationOnPhone
45 |
46 | UIApplicationSupportsIndirectInputEvents
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/example/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/example/lib/generated/assets.dart:
--------------------------------------------------------------------------------
1 | ///This file is automatically generated. DO NOT EDIT, all your changes would be lost.
2 | class Assets {
3 | Assets._();
4 |
5 | static const String assetsIcDebug = 'assets/ic_debug.png';
6 | static const String assetsIcDebugNative = 'assets/ic_debug_native.png';
7 | static const String assetsIcError = 'assets/ic_error.png';
8 | static const String assetsIcErrorAndroid = 'assets/ic_error_android.png';
9 | static const String assetsIcErrorIos = 'assets/ic_error_ios.png';
10 | static const String assetsIcHttp = 'assets/ic_http.png';
11 | static const String assetsIcJson = 'assets/ic_json.png';
12 | static const String assetsIcWarning = 'assets/ic_warning.png';
13 | static const String assetsIcWarningAndroid = 'assets/ic_warning_android.png';
14 | static const String assetsIcWarningIos = 'assets/ic_warning_ios.png';
15 | }
16 |
--------------------------------------------------------------------------------
/example/lib/rest_client.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:chopper/chopper.dart';
4 | import 'package:cr_logger/cr_logger.dart';
5 | import 'package:dio/dio.dart';
6 | import 'package:dio/io.dart';
7 |
8 | class RestClient {
9 | RestClient._() {
10 | dio = Dio()
11 | ..options.receiveTimeout = const Duration(milliseconds: _serverTimeout)
12 | ..options.connectTimeout = const Duration(milliseconds: _serverTimeout)
13 | ..options.sendTimeout = const Duration(milliseconds: _serverTimeout);
14 |
15 | dio.interceptors.add(
16 | CRLoggerInitializer.instance.getDioInterceptor(),
17 | );
18 | chopper = ChopperClient(interceptors: [
19 | CRLoggerInitializer.instance.getChopperInterceptor(),
20 | ]);
21 | }
22 |
23 | static const _serverTimeout = 15000;
24 | static final RestClient instance = RestClient._();
25 |
26 | late Dio dio;
27 | late ChopperClient chopper;
28 |
29 | /// Init proxy for Dio client.
30 | void initDioProxyForCharles(String proxy) {
31 | final split = proxy.split(':');
32 | final ip = split.first;
33 | final port = split[1];
34 |
35 | final proxyStr = 'PROXY $ip:$port; '
36 | 'PROXY localhost:$port; DIRECT';
37 | final adapter = dio.httpClientAdapter;
38 | if (adapter is IOHttpClientAdapter) {
39 | adapter.createHttpClient = () {
40 | final client = HttpClient(context: SecurityContext())
41 | ..findProxy = (uri) {
42 | return proxyStr;
43 | }
44 | ..badCertificateCallback = (
45 | X509Certificate cert,
46 | String host,
47 | int port,
48 | ) =>
49 | true;
50 |
51 | return client;
52 | };
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/example/lib/styles.dart:
--------------------------------------------------------------------------------
1 | class LoggerStyle {
2 | LoggerStyle._();
3 | }
4 |
--------------------------------------------------------------------------------
/example/lib/utils/try_cast.dart:
--------------------------------------------------------------------------------
1 | T? tryCast(Object? x) => x is T ? x : null;
2 |
--------------------------------------------------------------------------------
/example/lib/widgets/example_btn.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class ExampleBtn extends StatelessWidget {
4 | const ExampleBtn({
5 | required this.text,
6 | required this.assetName,
7 | required this.onTap,
8 | super.key,
9 | });
10 |
11 | final String text;
12 | final String assetName;
13 | final VoidCallback? onTap;
14 |
15 | @override
16 | Widget build(BuildContext context) {
17 | return ElevatedButton(
18 | onPressed: onTap,
19 | style: ElevatedButton.styleFrom(
20 | backgroundColor: Colors.white,
21 | shape: RoundedRectangleBorder(
22 | borderRadius: BorderRadius.circular(10),
23 | ),
24 | elevation: 0,
25 | minimumSize: const Size(0, 77),
26 | ),
27 | child: SizedBox(
28 | width: double.infinity,
29 | child: Column(
30 | crossAxisAlignment: CrossAxisAlignment.start,
31 | children: [
32 | const SizedBox(height: 14),
33 | Image.asset(
34 | assetName,
35 | height: 24,
36 | width: 24,
37 | ),
38 | const SizedBox(height: 8),
39 | Text(
40 | text,
41 | style: const TextStyle(
42 | fontWeight: FontWeight.w500,
43 | fontSize: 14,
44 | color: Colors.black,
45 | ),
46 | ),
47 | ],
48 | ),
49 | ),
50 | );
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/example/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: cr_logger_example
2 | description: Demonstrates how to use the cr_logger plugin.
3 | version: 1.0.0+1
4 |
5 | publish_to: 'none'
6 |
7 | environment:
8 | sdk: ">=3.0.0 <4.0.0"
9 | flutter: ">=3.16.0"
10 |
11 | dependencies:
12 | flutter:
13 | sdk: flutter
14 |
15 | cr_logger:
16 | path: ../
17 |
18 | dio: 5.4.0
19 | chopper: 7.0.10
20 | logger: 2.0.2+1
21 | flutter_dropzone: 3.0.6
22 | share_plus: 7.2.1
23 |
24 |
25 | dev_dependencies:
26 | flutter_test:
27 | sdk: flutter
28 |
29 | flutter:
30 | uses-material-design: true
31 | assets:
32 | - assets/
33 |
34 | fonts:
35 | - family: Epilogue
36 | fonts:
37 | - asset: fonts/Epilogue-Medium.ttf
38 | - asset: fonts/Epilogue-Regular.ttf
--------------------------------------------------------------------------------
/example/web/styles.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/example/web/styles.css
--------------------------------------------------------------------------------
/fonts/Epilogue-Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/fonts/Epilogue-Medium.ttf
--------------------------------------------------------------------------------
/fonts/Epilogue-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/fonts/Epilogue-Regular.ttf
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | .vagrant/
3 | .sconsign.dblite
4 | .svn/
5 |
6 | .DS_Store
7 | *.swp
8 | profile
9 |
10 | DerivedData/
11 | build/
12 | GeneratedPluginRegistrant.h
13 | GeneratedPluginRegistrant.m
14 |
15 | .generated/
16 |
17 | *.pbxuser
18 | *.mode1v3
19 | *.mode2v3
20 | *.perspectivev3
21 |
22 | !default.pbxuser
23 | !default.mode1v3
24 | !default.mode2v3
25 | !default.perspectivev3
26 |
27 | xcuserdata
28 |
29 | *.moved-aside
30 |
31 | *.pyc
32 | *sync/
33 | Icon?
34 | .tags*
35 |
36 | /Flutter/Generated.xcconfig
37 | /Flutter/ephemeral/
38 | /Flutter/flutter_export_environment.sh
--------------------------------------------------------------------------------
/ios/Assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/ios/Assets/.gitkeep
--------------------------------------------------------------------------------
/ios/Classes/CrLoggerPlugin.h:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | @interface CrLoggerPlugin : NSObject
4 | @end
5 |
--------------------------------------------------------------------------------
/ios/Classes/CrLoggerPlugin.m:
--------------------------------------------------------------------------------
1 | #import "CrLoggerPlugin.h"
2 | #if __has_include()
3 | #import
4 | #else
5 | // Support project import fallback if the generated compatibility header
6 | // is not copied when this plugin is created as a library.
7 | // https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816
8 | #import "cr_logger-Swift.h"
9 | #endif
10 |
11 | @implementation CrLoggerPlugin
12 | + (void)registerWithRegistrar:(NSObject*)registrar {
13 | [SwiftCrLoggerPlugin registerWithRegistrar:registrar];
14 | }
15 | @end
16 |
--------------------------------------------------------------------------------
/ios/Classes/SwiftCrLoggerPlugin.swift:
--------------------------------------------------------------------------------
1 | import Flutter
2 | import UIKit
3 |
4 | public class SwiftCrLoggerPlugin: NSObject, FlutterPlugin {
5 |
6 | public static func register(with registrar: FlutterPluginRegistrar) {
7 | let channel = FlutterMethodChannel(name: "cr_logger", binaryMessenger: registrar.messenger())
8 | let instance = SwiftCrLoggerPlugin()
9 | FlutterEventChannel(name: "com.cleveroad.cr_logger/logger", binaryMessenger: registrar.messenger())
10 | .setStreamHandler(CrLogger())
11 |
12 |
13 | registrar.addMethodCallDelegate(instance, channel: channel)
14 | }
15 |
16 | public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
17 | result("iOS " + UIDevice.current.systemVersion)
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/ios/cr_logger.podspec:
--------------------------------------------------------------------------------
1 | #
2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
3 | # Run `pod lib lint cr_logger.podspec` to validate before publishing.
4 | #
5 | Pod::Spec.new do |s|
6 | s.name = 'cr_logger'
7 | s.version = '0.0.1'
8 | s.summary = 'A new Flutter project.'
9 | s.description = <<-DESC
10 | A new Flutter project.
11 | DESC
12 | s.homepage = 'http://example.com'
13 | s.license = { :file => '../LICENSE' }
14 | s.author = { 'Your Company' => 'email@example.com' }
15 | s.source = { :path => '.' }
16 | s.source_files = 'Classes/**/*'
17 | s.dependency 'Flutter'
18 | s.platform = :ios, '11.0'
19 | s.ios.deployment_target = '11.0'
20 |
21 | # Flutter.framework does not contain a i386 slice.
22 | s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' }
23 | s.swift_version = '5.0'
24 |
25 | end
26 |
--------------------------------------------------------------------------------
/lib/cr_logger.dart:
--------------------------------------------------------------------------------
1 | library cr_logger;
2 |
3 | export 'src/cr_logger.dart';
4 | export 'src/cr_logger_wrapper.dart';
5 | export 'src/data/bean/error_bean.dart';
6 | export 'src/data/bean/http_bean.dart';
7 | export 'src/data/bean/log_bean.dart';
8 | export 'src/data/bean/request_bean.dart';
9 | export 'src/data/bean/response_bean.dart';
10 | export 'src/data/models/log_type.dart';
11 | export 'src/dio_log.dart';
12 | export 'src/extensions/ansi_color_ext.dart';
13 | export 'src/managers/http_log_manager.dart';
14 | export 'src/page/actions_and_values/models/notifier_data.dart';
15 | export 'src/widget/cr_inspector.dart';
16 |
--------------------------------------------------------------------------------
/lib/cr_logger_web.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | // In order to *not* need this ignore, consider extracting the "web" version
3 | // of your plugin as a separate package, instead of inlining it in the same
4 | // package as the core of your plugin.
5 | // ignore: avoid_web_libraries_in_flutter
6 | import 'dart:html' as html show window;
7 |
8 | import 'package:flutter/services.dart';
9 | import 'package:flutter_web_plugins/flutter_web_plugins.dart';
10 |
11 | /// A web implementation of the CrDownloader plugin.
12 | final class CrLoggerWeb {
13 | static void registerWith(Registrar registrar) {
14 | final channel = MethodChannel(
15 | 'cr_logger',
16 | const StandardMethodCodec(),
17 | registrar,
18 | );
19 |
20 | final pluginInstance = CrLoggerWeb();
21 | channel.setMethodCallHandler(pluginInstance.handleMethodCall);
22 | }
23 |
24 | /// Handles method calls over the MethodChannel of this plugin.
25 | /// Note: Check the "federated" architecture for a new way of doing this:
26 | /// https://flutter.dev/go/federated-plugins
27 | Future handleMethodCall(MethodCall call) async {
28 | switch (call.method) {
29 | case 'getPlatformVersion':
30 | return getPlatformVersion();
31 | default:
32 | throw PlatformException(
33 | code: 'Unimplemented',
34 | details: "cr_downloader for web doesn't implement '${call.method}'",
35 | );
36 | }
37 | }
38 |
39 | /// Returns a [String] containing the version of the platform.
40 | Future getPlatformVersion() {
41 | final version = html.window.navigator.userAgent;
42 |
43 | return Future.value(version);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/lib/generated/assets.dart:
--------------------------------------------------------------------------------
1 | ///This file is automatically generated. DO NOT EDIT, all your changes would be lost.
2 | class CRLoggerAssets {
3 | CRLoggerAssets._();
4 |
5 | static const String assetsArrowDown = 'assets/arrow_down.png';
6 | static const String assetsContentCopy = 'assets/content_copy.png';
7 | static const String assetsIcBack = 'assets/ic_back.png';
8 | static const String assetsIcMenu = 'assets/ic_menu.png';
9 | }
10 |
--------------------------------------------------------------------------------
/lib/src/base/base_page_with_progress.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/src/controllers/logs_mode.dart';
2 | import 'package:cr_logger/src/controllers/logs_mode_controller.dart';
3 | import 'package:cr_logger/src/res/colors.dart';
4 | import 'package:flutter/material.dart';
5 |
6 | abstract class BasePageWithProgress extends State {
7 | final _logsModeController = LogsModeController.instance;
8 |
9 | LogsMode get currentLogsMode => _logsModeController.logMode.value;
10 |
11 | @override
12 | void initState() {
13 | super.initState();
14 | _logsModeController.addListener(getCurrentLogs);
15 | }
16 |
17 | @override
18 | void dispose() {
19 | _logsModeController.removeListener(getCurrentLogs);
20 |
21 | super.dispose();
22 | }
23 |
24 | @override
25 | Widget build(BuildContext context) {
26 | return ValueListenableBuilder(
27 | valueListenable: _logsModeController.progressNotifier,
28 | //ignore: prefer-trailing-comma
29 | builder: (_, isProgressState, __) => isProgressState
30 | ? Container(
31 | color: CRLoggerColors.backgroundGrey.withOpacity(0.8),
32 | child: const Center(
33 | child: CircularProgressIndicator(),
34 | ),
35 | )
36 | : Builder(
37 | builder: (_) => bodyWidget(context),
38 | ),
39 | );
40 | }
41 |
42 | Widget bodyWidget(BuildContext context);
43 |
44 | Future getCurrentLogs();
45 | }
46 |
--------------------------------------------------------------------------------
/lib/src/constants.dart:
--------------------------------------------------------------------------------
1 | const kLoggerPackage = 'package:logger';
2 | const kLogFileName = 'log';
3 |
4 | const kMethodPost = 'POST';
5 | const kHidden = 'Hidden';
6 |
7 | const kMaxDuration = 3000;
8 | const kAverageDuration = 2000;
9 | const kMinDuration = 1000;
10 | const kWorkerId = 'worker1';
11 | const kRequestWorkerId = 'requestWorker';
12 | const kResponseWorkerId = 'responseWorker';
13 | const kErrorWorkerId = 'errorWorker';
14 | const kMs = 'ms';
15 | const kSending = 'Sending';
16 |
17 | /// Maximum number of each type of logs (http, debug, info, error) by default
18 | const kDefaultMaxLogsCount = 50;
19 |
20 | const kDefaultOfUrlCount = 4;
21 |
22 | /// Used to stop updating log list (if logs come too often)
23 | const kIndentForLoadingLogs = 100;
24 |
25 | final patternOfParamsRegex = RegExp(r'\{\{|\}\}');
26 |
--------------------------------------------------------------------------------
/lib/src/controllers/logs_mode.dart:
--------------------------------------------------------------------------------
1 | enum LogsMode {
2 | fromCurrentSession('Current logs'),
3 | fromDB('DB logs');
4 |
5 | const LogsMode(this.appBarTitle);
6 |
7 | final String appBarTitle;
8 | }
9 |
--------------------------------------------------------------------------------
/lib/src/controllers/logs_mode_controller.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/cr_logger.dart';
2 | import 'package:cr_logger/src/controllers/logs_mode.dart';
3 | import 'package:cr_logger/src/managers/log_manager.dart';
4 | import 'package:flutter/cupertino.dart';
5 |
6 | final class LogsModeController extends ChangeNotifier {
7 | LogsModeController._();
8 |
9 | static LogsModeController instance = LogsModeController._();
10 |
11 | final logMode = ValueNotifier(LogsMode.fromCurrentSession);
12 | final progressNotifier = ValueNotifier(false);
13 |
14 | bool get isFromCurrentSession => logMode.value == LogsMode.fromCurrentSession;
15 |
16 | bool _logsAreLoaded = false;
17 |
18 | Future changeMode() async {
19 | progressNotifier.value = false;
20 |
21 | if (logMode.value == LogsMode.fromCurrentSession) {
22 | logMode.value = LogsMode.fromDB;
23 | if (!_logsAreLoaded) {
24 | progressNotifier.value = true;
25 |
26 | await _loadLogsFromDB();
27 | progressNotifier.value = false;
28 | }
29 | _logsAreLoaded = true;
30 | } else {
31 | logMode.value = LogsMode.fromCurrentSession;
32 | }
33 | notifyListeners();
34 | }
35 |
36 | Future _loadLogsFromDB() => Future.wait([
37 | HttpLogManager.instance.loadLogsFromDB(),
38 | LogManager.instance.loadLogsFromDB(),
39 | ]);
40 | }
41 |
--------------------------------------------------------------------------------
/lib/src/cr_logger_helper.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/cr_logger.dart';
2 | import 'package:cr_logger/src/res/theme.dart';
3 | import 'package:flutter/foundation.dart';
4 | import 'package:flutter/material.dart';
5 | import 'package:package_info_plus/package_info_plus.dart';
6 | import 'package:shared_preferences/shared_preferences.dart';
7 | import 'package:synchronized/synchronized.dart';
8 |
9 | final class CRLoggerHelper {
10 | CRLoggerHelper._();
11 |
12 | static const _proxySharedPrefKey = 'cr_logger_charles_proxy';
13 | static CRLoggerHelper instance = CRLoggerHelper._();
14 |
15 | final lock = Lock();
16 | final inspectorNotifier = ValueNotifier(false);
17 | final loggerShowingNotifier = ValueNotifier(false);
18 |
19 | final maxLogsCount = CRLoggerInitializer.instance.maxCurrentLogsCount;
20 |
21 | final maxDBLogsCount = CRLoggerInitializer.instance.maxDBLogsCount;
22 | late final PackageInfo packageInfo;
23 | late final SharedPreferences _prefs;
24 |
25 | ThemeData theme = loggerTheme;
26 |
27 | bool get isLoggerShowing => loggerShowingNotifier.value;
28 |
29 | bool get useDB {
30 | final useCrLoggerInReleaseBuild =
31 | CRLoggerInitializer.instance.useCrLoggerInReleaseBuild;
32 | final useDB = CRLoggerInitializer.instance.useDB;
33 |
34 | return useDB && (useCrLoggerInReleaseBuild || !kReleaseMode) && !kIsWeb;
35 | }
36 |
37 | /// Condition that determines whether or not to print logs
38 | bool get printLogs {
39 | final printLogs = CRLoggerInitializer.instance.printLogs;
40 | final useCrLoggerInReleaseBuild =
41 | CRLoggerInitializer.instance.useCrLoggerInReleaseBuild;
42 |
43 | return printLogs && (useCrLoggerInReleaseBuild || !kReleaseMode);
44 | }
45 |
46 | Future init() async {
47 | _prefs = await SharedPreferences.getInstance();
48 | packageInfo = await PackageInfo.fromPlatform();
49 | }
50 |
51 | Future setProxyToSharedPref(String? proxy) async {
52 | return proxy != null
53 | ? _prefs.setString(_proxySharedPrefKey, proxy)
54 | : _prefs.remove(_proxySharedPrefKey);
55 | }
56 |
57 | String? getProxyFromSharedPref() => _prefs.getString(_proxySharedPrefKey);
58 |
59 | void showLogger() => loggerShowingNotifier.value = true;
60 |
61 | void hideLogger() => loggerShowingNotifier.value = false;
62 | }
63 |
--------------------------------------------------------------------------------
/lib/src/cr_logger_wrapper.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/src/log_message_wrapper.dart';
2 | import 'package:logger/logger.dart';
3 |
4 | final class CRLoggerWrapper {
5 | CRLoggerWrapper._();
6 |
7 | static final CRLoggerWrapper instance = CRLoggerWrapper._();
8 |
9 | late Logger log;
10 |
11 | /// It is necessary to be careful with the use of the [showToast] parameter,
12 | /// because at a high refresh rate the logs with this parameter will be missed
13 | /// for a detailed view.
14 | void t(
15 | dynamic message, {
16 | dynamic error,
17 | StackTrace? stackTrace,
18 | bool showToast = false,
19 | }) {
20 | log.t(
21 | LogMessageWrapper(
22 | message: message,
23 | showToast: showToast,
24 | ),
25 | error: error,
26 | stackTrace: stackTrace,
27 | );
28 | }
29 |
30 | void d(
31 | dynamic message, {
32 | dynamic error,
33 | StackTrace? stackTrace,
34 | bool showToast = false,
35 | }) {
36 | log.d(
37 | LogMessageWrapper(
38 | message: message,
39 | showToast: showToast,
40 | ),
41 | error: error,
42 | stackTrace: stackTrace,
43 | );
44 | }
45 |
46 | void i(
47 | dynamic message, {
48 | dynamic error,
49 | StackTrace? stackTrace,
50 | bool showToast = false,
51 | }) {
52 | log.i(
53 | LogMessageWrapper(
54 | message: message,
55 | showToast: showToast,
56 | ),
57 | error: error,
58 | stackTrace: stackTrace,
59 | );
60 | }
61 |
62 | void w(
63 | dynamic message, {
64 | dynamic error,
65 | StackTrace? stackTrace,
66 | bool showToast = false,
67 | }) {
68 | log.w(
69 | LogMessageWrapper(
70 | message: message,
71 | showToast: showToast,
72 | ),
73 | error: error,
74 | stackTrace: stackTrace,
75 | );
76 | }
77 |
78 | void e(
79 | dynamic message, {
80 | dynamic error,
81 | StackTrace? stackTrace,
82 | bool showToast = false,
83 | }) {
84 | log.e(
85 | LogMessageWrapper(
86 | message: message,
87 | showToast: showToast,
88 | ),
89 | error: error,
90 | stackTrace: stackTrace,
91 | );
92 | }
93 |
94 | void f(
95 | dynamic message, {
96 | dynamic error,
97 | StackTrace? stackTrace,
98 | bool showToast = false,
99 | }) {
100 | log.f(
101 | LogMessageWrapper(
102 | message: message,
103 | showToast: showToast,
104 | ),
105 | error: error,
106 | stackTrace: stackTrace,
107 | );
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/lib/src/data/bean/error_bean.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/src/data/bean/response_bean.dart';
2 |
3 | final class ErrorBean {
4 | ErrorBean({
5 | this.id,
6 | this.errorMessage,
7 | this.statusMessage,
8 | this.time,
9 | this.responseBean,
10 | this.duration,
11 | this.statusCode,
12 | this.baseUrl,
13 | this.url,
14 | this.errorData,
15 | });
16 |
17 | factory ErrorBean.fromJson(Map json) {
18 | return ErrorBean(
19 | id: json['id'],
20 | errorMessage: json['errorMessage'],
21 | url: json['url'],
22 | time: DateTime.tryParse(json['time'] ?? '')?.toLocal(),
23 | responseBean: ResponseBean.fromJson(json['responseBean']),
24 | duration: json['duration'],
25 | errorData: json['errorData'],
26 | );
27 | }
28 |
29 | int? id;
30 | dynamic errorData;
31 | String? errorMessage;
32 | String? statusMessage;
33 | String? baseUrl;
34 | String? url;
35 | DateTime? time;
36 | ResponseBean? responseBean;
37 | int? duration;
38 | int? statusCode;
39 |
40 | Map toJson() => {
41 | 'id': id,
42 | 'url': url,
43 | 'errorMessage': errorMessage,
44 | 'time': time?.toUtc().toString(),
45 | 'responseBean': responseBean?.toJson(),
46 | 'duration': duration,
47 | 'statusCode': statusCode,
48 | 'statusMessage': statusMessage,
49 | 'errorData': errorData?.toString(),
50 | };
51 | }
52 |
--------------------------------------------------------------------------------
/lib/src/data/bean/http_bean.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/src/data/bean/error_bean.dart' show ErrorBean;
2 | import 'package:cr_logger/src/data/bean/request_bean.dart' show RequestBean;
3 | import 'package:cr_logger/src/data/bean/response_bean.dart' show ResponseBean;
4 | import 'package:cr_logger/src/models/request_status.dart';
5 |
6 | final class HttpBean {
7 | HttpBean({
8 | this.key,
9 | this.request,
10 | this.response,
11 | this.error,
12 | });
13 |
14 | int? key;
15 | RequestBean? request;
16 | ResponseBean? response;
17 | ErrorBean? error;
18 | }
19 |
20 | extension HttpBeanExtension on HttpBean {
21 | RequestStatus get status {
22 | if (error != null) {
23 | return isInternetError ? RequestStatus.noInternet : RequestStatus.error;
24 | } else {
25 | //ignore: prefer-conditional-expressions
26 | if (response != null) {
27 | return response?.statusCode == null
28 | ? RequestStatus.error
29 | : RequestStatus.success;
30 | } else {
31 | return RequestStatus.sending;
32 | }
33 | }
34 | }
35 |
36 | bool get isInternetError {
37 | if (error?.statusCode != null) {
38 | return false;
39 | }
40 |
41 | final errorMessage = error?.errorMessage;
42 | if (errorMessage != null && errorMessage.contains('Connecting timed out')) {
43 | return true;
44 | }
45 |
46 | final errorData = error?.errorData;
47 | if (errorData is Map) {
48 | final errorCode = errorData['OS Error code'];
49 | if (errorCode == 7 ||
50 | errorCode == 8 ||
51 | errorCode == 101 ||
52 | errorCode == 103 ||
53 | errorData['No internet'] == true) {
54 | return true;
55 | }
56 | }
57 |
58 | return false;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/lib/src/data/bean/log_bean.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/cr_logger.dart';
2 | import 'package:cr_logger/src/res/colors.dart';
3 | import 'package:flutter/material.dart';
4 | import 'package:uuid/uuid.dart';
5 |
6 | final class LogBean implements Comparable {
7 | LogBean({
8 | required this.message,
9 | required this.time,
10 | required this.stackTrace,
11 | this.showToast = false,
12 | this.type,
13 | this.data = const {},
14 | this.key,
15 | String? id,
16 | }) : id = id ?? const Uuid().v4(),
17 | color = type?.getColor() ?? CRLoggerColors.primaryColor;
18 |
19 | final int? key;
20 | final String id;
21 | final dynamic message;
22 | final DateTime time;
23 | final String? stackTrace;
24 | final Map? data;
25 | LogType? type;
26 | Color color;
27 | bool showToast;
28 |
29 | @override
30 | int compareTo(LogBean other) {
31 | return other.time.isAfter(time) ? 1 : -1;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/lib/src/data/bean/response_bean.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/cr_logger.dart';
2 | import 'package:cr_logger/src/constants.dart';
3 | import 'package:cr_logger/src/utils/hide_values_in_map.dart';
4 |
5 | final class ResponseBean {
6 | ResponseBean({
7 | this.id,
8 | this.statusCode,
9 | this.url,
10 | this.method,
11 | this.statusMessage,
12 | this.responseTime,
13 | this.duration,
14 | this.data,
15 | this.headers,
16 | });
17 |
18 | factory ResponseBean.fromJson(Map json) {
19 | return ResponseBean(
20 | id: json['id'],
21 | statusCode: json['statusCode'],
22 | url: json['url'],
23 | method: json['method'],
24 | statusMessage: json['statusMessage'],
25 | responseTime: DateTime.tryParse(json['responseTime'] ?? '')?.toLocal(),
26 | duration: json['duration'],
27 | data: json['data'],
28 | headers: json['headers'],
29 | );
30 | }
31 |
32 | int? id;
33 | int? statusCode;
34 | String? url;
35 | String? method;
36 | String? statusMessage;
37 | DateTime? responseTime;
38 | int? duration;
39 | dynamic data;
40 | Map? headers;
41 |
42 | Map toJson() {
43 | final headers = {};
44 | this.headers?.forEach((k, list) => headers[k] = list.toString());
45 | final changedHeaders = headers.map((key, value) {
46 | return CRLoggerInitializer.instance.hiddenHeaders.contains(key)
47 | ? MapEntry(key, kHidden)
48 | : MapEntry(key, value);
49 | });
50 | Map? changedData;
51 | if (data is Map) {
52 | changedData = hideValuesInMap(data);
53 | }
54 |
55 | return {
56 | 'id': id,
57 | 'statusCode': statusCode,
58 | 'url': url,
59 | 'method': method,
60 | 'statusMessage': statusMessage,
61 | 'responseTime': responseTime?.toUtc().toString(),
62 | 'duration': duration,
63 | 'headers': changedHeaders,
64 | 'data': changedData,
65 | };
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/lib/src/data/models/log_type.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/src/res/colors.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:logger/logger.dart';
4 |
5 | enum LogType {
6 | http('HTTP'),
7 | debug('Debug'),
8 | info('Info'),
9 | error('Error');
10 |
11 | const LogType(this.name);
12 |
13 | Color getColor() {
14 | switch (this) {
15 | case LogType.http:
16 | return CRLoggerColors.blueAccent;
17 | case LogType.debug:
18 | return CRLoggerColors.greenAccent;
19 | case LogType.info:
20 | return CRLoggerColors.blueAccent;
21 | case LogType.error:
22 | return CRLoggerColors.red;
23 | }
24 | }
25 |
26 | static LogType? getTypeFromLevel(Level level) {
27 | switch (level) {
28 | case Level.trace:
29 | case Level.debug:
30 | return LogType.debug;
31 | case Level.info:
32 | case Level.warning:
33 | return LogType.info;
34 | case Level.error:
35 | case Level.fatal:
36 | return LogType.error;
37 | default:
38 | return null;
39 | }
40 | }
41 |
42 | final String name;
43 | }
44 |
--------------------------------------------------------------------------------
/lib/src/data/sqflite_db/converters/http_enitity_converter.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/cr_logger.dart';
2 | import 'package:cr_logger/src/data/sqflite_db/entities/http_entity.dart';
3 | import 'package:cr_logger/src/utils/parsers/isolate_parser.dart';
4 |
5 | final class HttpEntityConverter {
6 | final _parser = IsolateParser();
7 |
8 | Future inToOut(HttpEntity inObject) async {
9 | final request = await _decode(inObject.request);
10 | final response = await _decode(inObject.response);
11 | final error = await _decode(inObject.error);
12 |
13 | return HttpBean(
14 | key: inObject.key,
15 | request: request != null ? RequestBean.fromJson(request) : null,
16 | response: response != null ? ResponseBean.fromJson(response) : null,
17 | error: error != null ? ErrorBean.fromJson(error) : null,
18 | );
19 | }
20 |
21 | Future outToIn(HttpBean outObject) async {
22 | final request = outObject.request;
23 | final response = outObject.response;
24 | final error = outObject.error;
25 |
26 | return HttpEntity(
27 | key: outObject.key,
28 | request: await _encode(request, request?.toJson()),
29 | response: await _encode(response, response?.toJson()),
30 | error: await _encode(error, error?.toJson()),
31 | );
32 | }
33 |
34 | dynamic _decode(String? json) async =>
35 | json != null ? await _parser.decode(json) : null;
36 |
37 | Future _encode(dynamic object, Map? json) async =>
38 | object != null ? await _parser.encode(json) : null;
39 | }
40 |
--------------------------------------------------------------------------------
/lib/src/data/sqflite_db/converters/log_entity_converters.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/cr_logger.dart';
2 | import 'package:cr_logger/src/data/sqflite_db/entities/log_entity.dart';
3 | import 'package:cr_logger/src/utils/parsers/isolate_parser.dart';
4 |
5 | final class LogEntityConverter {
6 | final _parser = IsolateParser();
7 |
8 | Future inToOut(LogEntity inObject) async {
9 | final data = inObject.data;
10 |
11 | return LogBean(
12 | id: inObject.id,
13 | message: await _parser.decode(inObject.message),
14 | time: inObject.time?.toLocal() ?? DateTime.now(),
15 | stackTrace: inObject.stackTrace,
16 | data: data != null ? await _parser.decode(data) : null,
17 | key: inObject.key,
18 | type: inObject.type,
19 | );
20 | }
21 |
22 | Future outToIn(LogBean outObject) async {
23 | final data = outObject.data;
24 |
25 | return LogEntity(
26 | message: await _parser.encode(outObject.message),
27 | time: outObject.time.toUtc(),
28 | stackTrace: outObject.stackTrace,
29 | data: data != null && data.isNotEmpty ? await _parser.encode(data) : null,
30 | type: outObject.type ?? LogType.info,
31 | id: outObject.id,
32 | key: outObject.key ?? 0,
33 | );
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/lib/src/data/sqflite_db/entities/http_entity.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/src/utils/map_ext.dart';
2 |
3 | final class HttpEntity {
4 | HttpEntity({
5 | this.key,
6 | this.request,
7 | this.response,
8 | this.error,
9 | });
10 |
11 | factory HttpEntity.fromJson(Map json) {
12 | return HttpEntity(
13 | /// Here it is checked for type because after importing the logs to the Web,
14 | /// in the json file the [key] is saved as a 'String'.
15 | /// But in the db the key is stored in 'int'.
16 | key: json['key'] is String ? int.tryParse(json['key']) : json['key'],
17 | request: json['request'],
18 | response: json['response'],
19 | error: json['error'],
20 | );
21 | }
22 |
23 | int? key;
24 | String? request;
25 | String? response;
26 | String? error;
27 |
28 | Map toJson() {
29 | final json = {
30 | 'key': key?.toString(),
31 | 'request': request,
32 | 'response': response,
33 | 'error': error,
34 | };
35 |
36 | // ignore: cascade_invocations
37 | json.clearAllNull();
38 |
39 | return json;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/lib/src/data/sqflite_db/entities/log_entity.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/cr_logger.dart';
2 | import 'package:cr_logger/src/utils/enum_ext.dart';
3 | import 'package:cr_logger/src/utils/map_ext.dart';
4 |
5 | final class LogEntity {
6 | LogEntity({
7 | required this.id,
8 | required this.message,
9 | required this.time,
10 | required this.stackTrace,
11 | required this.type,
12 | this.data = '',
13 | this.key,
14 | });
15 |
16 | factory LogEntity.fromJson(Map json) {
17 | return LogEntity(
18 | key: json['key'],
19 | message: json['message'],
20 | time: DateTime.tryParse(json['time'])?.toLocal(),
21 | stackTrace: json['stacktrace'],
22 | type: LogType.values.valueOf(json['type']) ?? LogType.info,
23 | data: json['data'],
24 | id: json['id'],
25 | );
26 | }
27 |
28 | final int? key;
29 | final String id;
30 | final String message;
31 | final DateTime? time;
32 | final String? stackTrace;
33 | final String? data;
34 | final LogType type;
35 |
36 | /// [key] should not be in this method, because the database increments it itself.
37 | Map toJson() {
38 | final json = {
39 | 'id': id,
40 | 'message': message.toString(),
41 | 'time': time?.toUtc().toString(),
42 | 'stacktrace': stackTrace?.toString(),
43 | 'data': data?.toString(),
44 | 'type': type.name.toString(),
45 | };
46 |
47 | // ignore: cascade_invocations
48 | json.clearAllNull();
49 |
50 | return json;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/lib/src/data/sqflite_db/log_module.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/cr_logger.dart';
2 | import 'package:cr_logger/src/data/sqflite_db/converters/http_enitity_converter.dart';
3 | import 'package:cr_logger/src/data/sqflite_db/converters/log_entity_converters.dart';
4 | import 'package:cr_logger/src/data/sqflite_db/sqflite_repository.dart';
5 |
6 | final class LogModule {
7 | LogModule._();
8 |
9 | static LogModule instance = LogModule._();
10 |
11 | final _httpLogConverter = HttpEntityConverter();
12 | final _logConverter = LogEntityConverter();
13 |
14 | final _sqlRepository = SqfliteRepository.instance;
15 |
16 | Future init() async {
17 | await _sqlRepository.initDB();
18 | }
19 |
20 | /// Http Log
21 | Future> getAllSavedHttpLogs() async {
22 | final logs = await _sqlRepository.getAllHttpLogs();
23 | final logModel = [];
24 | for (final log in logs) {
25 | logModel.add(await _httpLogConverter.inToOut(log));
26 | }
27 |
28 | return logModel;
29 | }
30 |
31 | Future saveHttpLog(HttpBean httpLog) async =>
32 | _sqlRepository.saveHTTPLog(
33 | await _httpLogConverter.outToIn(httpLog),
34 | );
35 |
36 | Future updateHttpLog(HttpBean httpLog) async =>
37 | _sqlRepository.updateHTTPLog(
38 | await _httpLogConverter.outToIn(httpLog),
39 | );
40 |
41 | Future deleteAllHttpLogs() => _sqlRepository.deleteAllHttpLogs();
42 |
43 | Future deleteHttpLogs(List logs) async {
44 | final ids = logs.map((e) => e.key).whereType().toList();
45 |
46 | return _sqlRepository.deleteHttpLogs(ids);
47 | }
48 |
49 | /// Logs
50 | Future> getAllSavedLogs() async {
51 | final logs = await _sqlRepository.getAllLogs();
52 | final logModel = [];
53 | for (final log in logs) {
54 | logModel.add(await _logConverter.inToOut(log));
55 | }
56 |
57 | return logModel;
58 | }
59 |
60 | Future saveLog(LogBean log) async => _sqlRepository.saveLog(
61 | await _logConverter.outToIn(log),
62 | );
63 |
64 | Future deleteAllLogs() => _sqlRepository.deleteAllLogs();
65 |
66 | Future deleteLogs(List logs) async {
67 | final ids = logs.map((e) => e.key).whereType().toList();
68 |
69 | return _sqlRepository.deleteLogs(ids);
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/lib/src/dio_log.dart:
--------------------------------------------------------------------------------
1 | export 'interceptor/chopper_log_interceptor.dart';
2 | export 'interceptor/dio_log_interceptor.dart';
3 | export 'managers/http_log_manager.dart';
4 | export 'overlay_draggable_button.dart';
5 | export 'utils/copy_clipboard.dart';
6 | export 'utils/json_utils.dart';
7 | export 'widget/http_error_widget.dart';
8 | export 'widget/http_request_widget.dart';
9 | export 'widget/http_response_widget.dart';
10 |
--------------------------------------------------------------------------------
/lib/src/extensions/ansi_color_ext.dart:
--------------------------------------------------------------------------------
1 | import 'dart:ui';
2 |
3 | import 'package:logger/logger.dart';
4 |
5 | extension AnsiColorExt on AnsiColor {
6 | /// Return [AnsiColor] from provided [color] or null if [color] is null.
7 | static AnsiColor? fromColorOrNull(Color? color) =>
8 | (color != null) ? fromColor(color) : null;
9 |
10 | /// Return [AnsiColor] from provided [color]
11 | static AnsiColor fromColor(Color color) {
12 | var xtermColor = ((color.red / 255).clamp(0.0, 1.0) * 5).toInt() * 36 +
13 | ((color.green / 255).clamp(0.0, 1.0) * 5).toInt() * 6 +
14 | ((color.blue / 255).clamp(0.0, 1.0) * 5).toInt() +
15 | 16;
16 |
17 | xtermColor = xtermColor < 0
18 | ? 0
19 | : xtermColor > 255
20 | ? 255
21 | : xtermColor;
22 |
23 | return AnsiColor.fg(xtermColor);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/lib/src/extensions/card_theme_ext.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | extension CardThemeExt on CardTheme {
4 | BorderRadius get borderRadius =>
5 | ((shape ?? const RoundedRectangleBorder()) as RoundedRectangleBorder)
6 | .borderRadius as BorderRadius;
7 | }
8 |
--------------------------------------------------------------------------------
/lib/src/extensions/cast.dart:
--------------------------------------------------------------------------------
1 | T? cast(Object? x) => x is T ? x : null;
2 |
--------------------------------------------------------------------------------
/lib/src/extensions/date_time.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/src/extensions/int_ext.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | extension DateTimeFormatter on DateTime {
5 | /// The same as [DateFormat('yyyy MM dd hh:mm:ss.SSS').format(this)]
6 | String formatTimeWithYear(BuildContext context) =>
7 | '$year-${month.leading}-${day.leading} ${formatTime(context)}';
8 |
9 | /// The same as [DateFormat('hh:mm:ss.SSS').format(this)]
10 | String formatTime(BuildContext context) {
11 | final userUse24HourFormat = MediaQuery.of(context).alwaysUse24HourFormat;
12 |
13 | return userUse24HourFormat
14 | ? '${hour.leading}:${minute.leading}:${second.leading}.${millisecond.leading3}'
15 | : formatted12HourString;
16 | }
17 |
18 | // TODO: make this using intl package later, when all packages move to 0.18.0 version
19 | /// Returns time from DateTime in 12H format (19:35 => 07:35 PM)
20 | String get formatted12HourString {
21 | final time = TimeOfDay.fromDateTime(this);
22 | final buffer = StringBuffer();
23 | final hours12hFormat = time.hour - time.periodOffset;
24 | final hoursStr =
25 | hours12hFormat < 10 ? '0$hours12hFormat' : hours12hFormat.toString();
26 | final minutesStr =
27 | time.minute < 10 ? '0${time.minute}' : time.minute.toString();
28 | final periodStr = time.period.name;
29 | buffer.writeAll([
30 | hoursStr,
31 | ':',
32 | minutesStr,
33 | ' ',
34 | periodStr,
35 | ]);
36 |
37 | return buffer.toString().toUpperCase();
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/lib/src/extensions/do_post_frame.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | extension StateExt on State {
4 | void doPostFrame(Function func) {
5 | WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
6 | func();
7 | });
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/lib/src/extensions/extensions.dart:
--------------------------------------------------------------------------------
1 | export 'ansi_color_ext.dart';
2 | export 'card_theme_ext.dart';
3 | export 'cast.dart';
4 | export 'date_time.dart';
5 | export 'image_ext.dart';
6 | export 'int_ext.dart';
7 | export 'theme_data_ext.dart';
8 |
--------------------------------------------------------------------------------
/lib/src/extensions/image_ext.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | extension ImageExt on Image {
4 | static Image fromPackage(
5 | String name, {
6 | double width = 24,
7 | double height = 24,
8 | }) =>
9 | Image.asset(
10 | name,
11 | package: 'cr_logger',
12 | width: width,
13 | height: height,
14 | );
15 | }
16 |
--------------------------------------------------------------------------------
/lib/src/extensions/int_ext.dart:
--------------------------------------------------------------------------------
1 | extension IntExt on int {
2 | String toStringWithLeading([int width = 2, String symbol = '0']) =>
3 | toString().padLeft(width, symbol);
4 |
5 | String get leading => toStringWithLeading();
6 |
7 | String get leading3 => toStringWithLeading(3);
8 | }
9 |
--------------------------------------------------------------------------------
/lib/src/extensions/theme_data_ext.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | extension ThemeDataExt on ThemeData {
4 | /// Return ThemeData with default values of [cardTheme] fields
5 | ThemeData copyWithDefaultCardTheme(CardTheme defaultCardTheme) {
6 | return copyWith(
7 | cardTheme: cardTheme.copyWith(
8 | clipBehavior: cardTheme.clipBehavior ?? defaultCardTheme.clipBehavior,
9 | color: cardTheme.color ?? defaultCardTheme.color,
10 | shadowColor: cardTheme.shadowColor ?? defaultCardTheme.shadowColor,
11 | elevation: cardTheme.elevation ?? defaultCardTheme.elevation,
12 | margin: cardTheme.margin ?? defaultCardTheme.margin,
13 | shape: cardTheme.shape ?? defaultCardTheme.shape,
14 | ),
15 | );
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/lib/src/interceptor/chopper_log_interceptor.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | import 'dart:convert';
3 |
4 | import 'package:chopper/chopper.dart';
5 | import 'package:cr_logger/cr_logger.dart';
6 | import 'package:http/http.dart' as http;
7 |
8 | final class ChopperLogInterceptor
9 | implements ResponseInterceptor, RequestInterceptor {
10 | final logManager = HttpLogManager.instance;
11 |
12 | @override
13 | FutureOr onRequest(Request request) async {
14 | final reqOpt = RequestBean()
15 | ..id = _getRequestHashCode(await request.toBaseRequest())
16 | ..url = request.url.toString()
17 | ..method = request.method
18 | ..contentType = request.headers['Content-Type'].toString()
19 | ..requestTime = DateTime.now()
20 | ..params = request.parameters
21 | ..body = request.body
22 | ..headers = request.headers;
23 | logManager.onRequest(reqOpt);
24 |
25 | return request;
26 | }
27 |
28 | @override
29 | FutureOr onResponse(Response response) {
30 | var data = {};
31 | try {
32 | data = json.decode(response.body as String);
33 | } catch (error, stackTrace) {
34 | log.e(
35 | 'Chopper interceptor error',
36 | error: error,
37 | stackTrace: stackTrace,
38 | );
39 | }
40 |
41 | final requestId = _getRequestHashCode(response.base.request!);
42 | final statusCode = response.statusCode;
43 | final isError = statusCode < 200 || statusCode >= 300;
44 |
45 | /// In error case, do not put data in ResponseBean.
46 | final dynamic responseData;
47 | //ignore: prefer-conditional-expressions
48 | if (isError) {
49 | responseData = null;
50 | } else {
51 | responseData = data.isNotEmpty ? data : response.body;
52 | }
53 |
54 | final responseBean = ResponseBean()
55 | ..id = requestId
56 | ..responseTime = DateTime.now()
57 | ..statusCode = response.statusCode
58 | ..url = response.base.request?.url.toString()
59 | ..method = response.base.request?.method
60 | ..statusMessage = response.base.reasonPhrase
61 | ..data = responseData
62 | ..headers = response.headers;
63 | logManager.onResponse(responseBean);
64 |
65 | /// On error
66 | if (isError) {
67 | final errorBean = ErrorBean()
68 | ..id = requestId
69 | ..errorData = response.error
70 | ..statusCode = statusCode
71 | ..statusMessage = response.base.reasonPhrase
72 | ..url = response.base.request?.url.toString()
73 | ..time = DateTime.now();
74 | logManager.onError(errorBean);
75 | }
76 |
77 | return response;
78 | }
79 |
80 | /// Creates hashcode based on request
81 | int _getRequestHashCode(http.BaseRequest baseRequest) {
82 | var hashCodeSum = 0;
83 |
84 | hashCodeSum += baseRequest.url.hashCode;
85 | hashCodeSum += baseRequest.method.hashCode;
86 | if (baseRequest.headers.isNotEmpty) {
87 | baseRequest.headers.forEach((key, value) {
88 | hashCodeSum += key.hashCode;
89 | hashCodeSum += value.hashCode;
90 | });
91 | }
92 | if (baseRequest.contentLength != null) {
93 | hashCodeSum += baseRequest.contentLength.hashCode;
94 | }
95 |
96 | return hashCodeSum.hashCode;
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/lib/src/interceptor/cr_http_adapter.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/cr_logger.dart';
2 | import 'package:http/http.dart' as http;
3 |
4 | final class CRHttpAdapter {
5 | HttpLogManager logManager = HttpLogManager.instance;
6 |
7 | /// Handles http response. It creates both request and response from http call
8 | void onResponse(http.Response response, Object? body) {
9 | if (response.request == null) {
10 | return;
11 | }
12 | final request = response.request!;
13 |
14 | final requestHeaders = {};
15 |
16 | request.headers.forEach((header, value) {
17 | requestHeaders[header] = value;
18 | });
19 |
20 | String? contentType = 'unknown';
21 | if (requestHeaders.containsKey('Content-Type')) {
22 | contentType = requestHeaders['Content-Type'] as String?;
23 | }
24 |
25 | final requestBean = RequestBean()
26 | ..id = request.hashCode
27 | ..url = request.url.toString()
28 | ..method = request.method
29 | ..contentType = contentType
30 | ..requestTime = DateTime.now()
31 | ..body = body
32 | ..headers = requestHeaders;
33 | logManager.onRequest(requestBean);
34 |
35 | final responseHeaders = {};
36 |
37 | response.headers.forEach((header, value) {
38 | responseHeaders[header] = value;
39 | });
40 |
41 | final statusCode = response.statusCode;
42 | final isError = statusCode < 200 || statusCode >= 300;
43 |
44 | final responseBean = ResponseBean()
45 | ..id = request.hashCode
46 | ..responseTime = DateTime.now()
47 | ..url = request.url.toString()
48 | ..method = request.method
49 | ..statusCode = response.statusCode
50 | ..statusMessage = response.reasonPhrase
51 |
52 | /// In error case, do not put data in ResponseBean.
53 | ..data = isError ? null : body
54 | ..headers = responseHeaders;
55 | logManager.onResponse(responseBean);
56 |
57 | /// On error
58 | if (isError) {
59 | final errorBean = ErrorBean()
60 | ..id = request.hashCode
61 | ..url = request.url.toString()
62 | ..time = DateTime.now()
63 | ..statusCode = response.statusCode
64 | ..statusMessage = response.reasonPhrase;
65 | logManager.onError(errorBean);
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/lib/src/interceptor/cr_http_client_adapter.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:cr_logger/cr_logger.dart';
4 |
5 | final class CRHttpClientAdapter {
6 | HttpLogManager logManager = HttpLogManager.instance;
7 |
8 | /// Handles httpClientRequest and creates http alice call from it
9 | void onRequest(HttpClientRequest request, Object? body) {
10 | final headers = {};
11 |
12 | request.headers.forEach((header, value) {
13 | headers[header] = value;
14 | });
15 |
16 | String? contentType = 'unknown';
17 | if (headers.containsKey('Content-Type')) {
18 | contentType = headers['Content-Type'] as String?;
19 | }
20 |
21 | final reqOpt = RequestBean()
22 | ..id = request.hashCode
23 | ..url = request.uri.toString()
24 | ..method = request.method
25 | ..contentType = contentType
26 | ..requestTime = DateTime.now()
27 | ..body = body
28 | ..headers = headers;
29 |
30 | logManager.onRequest(reqOpt);
31 | }
32 |
33 | /// Handles httpClientRequest and adds response to http alice call
34 | void onResponse(
35 | HttpClientResponse response,
36 | HttpClientRequest request,
37 | Object? body,
38 | ) {
39 | final headers = {};
40 |
41 | response.headers.forEach((header, value) {
42 | headers[header] = value;
43 | });
44 |
45 | final statusCode = response.statusCode;
46 | final isError = statusCode < 200 || statusCode >= 300;
47 |
48 | final resOpt = ResponseBean()
49 | ..id = request.hashCode
50 | ..responseTime = DateTime.now()
51 | ..url = request.uri.toString()
52 | ..method = request.method
53 | ..statusCode = response.statusCode
54 | ..statusMessage = response.reasonPhrase
55 |
56 | /// In error case, do not put data in ResponseBean.
57 | ..data = isError ? null : body
58 | ..headers = headers;
59 | logManager.onResponse(resOpt);
60 |
61 | /// On error
62 | if (isError) {
63 | final errorBean = ErrorBean()
64 | ..id = request.hashCode
65 | ..url = request.uri.toString()
66 | ..time = DateTime.now()
67 | ..statusCode = response.statusCode
68 | ..statusMessage = response.reasonPhrase;
69 | logManager.onError(errorBean);
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/lib/src/js/console_output_worker.dart:
--------------------------------------------------------------------------------
1 | @JS()
2 | library console_output;
3 |
4 | // ignore: avoid_web_libraries_in_flutter
5 | import 'package:cr_logger/src/utils/html_stub.dart'
6 | if (dart.library.js) 'package:js/js.dart';
7 |
8 | @JS('printLogs')
9 | external void printLogs(List lines);
10 |
11 | @JS('printRequestLog')
12 | external void printRequestLog(String requestBean);
13 |
14 | @JS('printResponseLog')
15 | external void printResponseLog(String responseBean);
16 |
17 | @JS('printErrorLog')
18 | external void printErrorLog(String errorBean);
19 |
20 | @JS('downloadLogsWeb')
21 | external void downloadLogsWeb(String fileName, String text);
22 |
--------------------------------------------------------------------------------
/lib/src/js/error_worker_scripts.dart:
--------------------------------------------------------------------------------
1 | const errorWorkerScript = r'''
2 | self.onmessage = function (e) {
3 | let errorBean = JSON.parse(e.data)
4 | console.log(errorBean)
5 | if (errorBean["responseBean"] != null) {
6 | let uri = errorBean["url"];
7 | printBoxed(
8 | `Error ║ Status: ${errorBean["statusCode"]} ${errorBean["statusMessage"]}`,
9 | uri.toString(),
10 | );
11 | if (errorBean["errorMessage"] != null && errorBean["responseBean"] != null) {
12 | let responseBean = errorBean["responseBean"]
13 | printMapAsTable(new Map(Object.entries(responseBean["headers"])), 'Headers');
14 | console.log('╔ Body');
15 | console.log('║')
16 | if (responseBean["data"] != null) {
17 | if (responseBean["data"] instanceof Object) {
18 | printPrettyMap(new Map(Object.entries(responseBean["data"])));
19 | } else if (responseBean["data"] instanceof Array) {
20 | console.log(`║ [`);
21 | printList(responseBean["data"]);
22 | console.log(`║ [`);
23 | } else {
24 | printBlock(responseBean["data"].toString());
25 | }
26 | }
27 | console.log('║');
28 | printLine('╚');
29 | } else {
30 | printLine('╚');
31 | console.log('');
32 | }
33 | } else {
34 | printBoxed(
35 | 'Error ║ ',
36 | errorBean["errorMessage"],
37 | );
38 | }
39 | };
40 | ''';
41 |
42 | const createErrorWorkerScript = '''
43 | var errorBlob = new Blob([
44 | document.querySelector('#errorWorker').textContent
45 | ], { type: "text/javascript" })
46 |
47 | var errorWorker = new Worker(window.URL.createObjectURL(errorBlob));
48 | ''';
49 |
50 | const printErrorLogScript = '''
51 | function printErrorLog(errorBean) {
52 | errorWorker.postMessage(errorBean);
53 | }
54 | ''';
55 |
--------------------------------------------------------------------------------
/lib/src/js/request_worker_scripts.dart:
--------------------------------------------------------------------------------
1 | const requestWorkerScript = '''
2 | self.onmessage = function (e) {
3 | let requestBean = JSON.parse(e.data)
4 |
5 | printRequestHeader(requestBean)
6 | printMapAsTable(new Map(Object.entries(requestBean["params"])), 'Query Parameters');
7 | printMapAsTable(new Map(Object.entries(requestBean["headers"])), 'Headers');
8 |
9 | if (requestBean["method"] != 'GET') {
10 | let data = requestBean["body"];
11 | if (data != null) {
12 | if (data instanceof Object) {
13 | printMapAsTable(new Map(Object.entries(data)), 'Body');
14 | }
15 | else {
16 | printBlock(data.toString());
17 | }
18 | }
19 | }
20 | };
21 | ''';
22 |
23 | const createRequestWorkerScript = '''
24 | var requestBlob = new Blob([
25 | document.querySelector('#requestWorker').textContent
26 | ], { type: "text/javascript" })
27 |
28 | var requestWorker = new Worker(window.URL.createObjectURL(requestBlob));
29 | ''';
30 |
31 | const printRequestLogScript = '''
32 | function printRequestLog(requestBean) {
33 | requestWorker.postMessage(requestBean);
34 | }
35 | ''';
36 |
--------------------------------------------------------------------------------
/lib/src/js/response_worker_scripts.dart:
--------------------------------------------------------------------------------
1 | const responseWorkerScript = '''
2 | self.onmessage = function (e) {
3 | let responseBean = JSON.parse(e.data)
4 |
5 | printResponse(responseBean)
6 | };
7 | ''';
8 |
9 | const createResponseWorkerScript = '''
10 | var responseBlob = new Blob([
11 | document.querySelector('#responseWorker').textContent
12 | ], { type: "text/javascript" })
13 |
14 | var responseWorker = new Worker(window.URL.createObjectURL(responseBlob));
15 | ''';
16 |
17 | const printResponseLogScript = '''
18 | function printResponseLog(responseBean) {
19 | responseWorker.postMessage(responseBean);
20 | }
21 | ''';
22 |
--------------------------------------------------------------------------------
/lib/src/js/scripts.dart:
--------------------------------------------------------------------------------
1 | const workerScript = '''
2 | self.onmessage = function(e) {
3 | e.data.forEach(
4 | function(line) {
5 | console.log(line);
6 | }
7 | );
8 | };
9 | ''';
10 |
11 | const createWorkerScript = '''
12 | var blob = new Blob([
13 | document.querySelector('#worker1').textContent
14 | ], { type: "text/javascript" })
15 |
16 | var worker = new Worker(window.URL.createObjectURL(blob));
17 | ''';
18 |
19 | const printLogsScript = '''
20 | function printLogs(lines) {
21 | worker.postMessage(lines); // Start the worker.
22 | }
23 | ''';
24 |
25 | const downloadLogsWebScript = '''
26 | function downloadLogsWeb(fileName, text) {
27 | var element = document.createElement('a');
28 | element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
29 | element.setAttribute('download', fileName);
30 |
31 | element.style.display = 'none';
32 | document.body.appendChild(element);
33 | element.click()
34 | element.remove()
35 | }
36 | ''';
37 |
--------------------------------------------------------------------------------
/lib/src/log_message_wrapper.dart:
--------------------------------------------------------------------------------
1 | /// Log message wrapper allowing to add new parameters
2 | class LogMessageWrapper {
3 | LogMessageWrapper({
4 | required this.message,
5 | required this.showToast,
6 | });
7 |
8 | dynamic message;
9 | bool showToast;
10 | }
11 |
--------------------------------------------------------------------------------
/lib/src/models/http_log_type.dart:
--------------------------------------------------------------------------------
1 | enum HttpLogType {
2 | request,
3 | response,
4 | error,
5 | }
6 |
7 | extension HttpLogTypeExt on HttpLogType {
8 | String asString() {
9 | switch (this) {
10 | case HttpLogType.request:
11 | return 'Request';
12 | case HttpLogType.response:
13 | return 'Response';
14 | case HttpLogType.error:
15 | return 'Error';
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/lib/src/models/request_status.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/src/res/colors.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | enum RequestStatus {
5 | sending(CRLoggerColors.yellow),
6 | success(CRLoggerColors.green),
7 | error(CRLoggerColors.red),
8 | noInternet(CRLoggerColors.red);
9 |
10 | const RequestStatus(this.color);
11 |
12 | final Color color;
13 | }
14 |
--------------------------------------------------------------------------------
/lib/src/page/actions_and_values/actions_manager.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/src/page/actions_and_values/models/action_model.dart';
2 | import 'package:flutter/foundation.dart';
3 |
4 | /// Manager through which methods are added to the page
5 | final class ActionsManager {
6 | ActionsManager._();
7 |
8 | static final List actions = [];
9 |
10 | static void addActionButton(
11 | String text,
12 | VoidCallback action, {
13 | String? connectedWidgetId,
14 | }) {
15 | actions.add(ActionModel(
16 | text: text,
17 | action: action,
18 | connectedWidgetId: connectedWidgetId,
19 | ));
20 | }
21 |
22 | static void removeActionButtonsById(String connectedWidgetId) {
23 | actions.removeWhere((action) {
24 | return action.connectedWidgetId == connectedWidgetId;
25 | });
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/lib/src/page/actions_and_values/models/action_model.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/foundation.dart';
2 |
3 | /// Action data model for [ActionsManager]
4 | final class ActionModel {
5 | ActionModel({
6 | required this.text,
7 | required this.action,
8 | this.connectedWidgetId,
9 | });
10 |
11 | final String text;
12 | final VoidCallback action;
13 | final String? connectedWidgetId;
14 | }
15 |
--------------------------------------------------------------------------------
/lib/src/page/actions_and_values/models/notifier_data.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | /// Model value notifier
4 | final class NotifierData {
5 | NotifierData({
6 | required this.valueNotifier,
7 | this.widget,
8 | this.name,
9 | this.connectedWidgetId,
10 | }) : assert(
11 | valueNotifier == null && name == null && widget != null ||
12 | valueNotifier != null && name != null && widget == null,
13 | "if widget is null, then name and valueNotifier can't be null and conversely",
14 | );
15 |
16 | final String? name;
17 | final ValueNotifier? valueNotifier;
18 | final Widget? widget;
19 | final String? connectedWidgetId;
20 | }
21 |
--------------------------------------------------------------------------------
/lib/src/page/actions_and_values/notifiers_manager.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/src/page/actions_and_values/models/notifier_data.dart';
2 | import 'package:flutter/cupertino.dart';
3 |
4 | /// Manager through which value notifiers are added to the page
5 | final class NotifiersManager {
6 | NotifiersManager._();
7 |
8 | static final List valueNotifiers = [];
9 |
10 | static void addNotifier({
11 | ValueNotifier? notifier,
12 | Widget? widget,
13 | String? name,
14 | String? connectedWidgetId,
15 | }) {
16 | valueNotifiers.add(
17 | NotifierData(
18 | name: name,
19 | valueNotifier: notifier,
20 | widget: widget,
21 | connectedWidgetId: connectedWidgetId,
22 | ),
23 | );
24 | }
25 |
26 | static void removeNotifiersById(String connectedWidgetId) {
27 | valueNotifiers.removeWhere((notifier) {
28 | return notifier.connectedWidgetId == connectedWidgetId;
29 | });
30 | }
31 |
32 | static void clear() {
33 | valueNotifiers.clear();
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/lib/src/page/actions_and_values/widgets/action_item.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/src/page/actions_and_values/models/action_model.dart';
2 | import 'package:cr_logger/src/res/colors.dart';
3 | import 'package:flutter/material.dart';
4 |
5 | class ActionItem extends StatelessWidget {
6 | const ActionItem({
7 | required this.actionModel,
8 | super.key,
9 | });
10 |
11 | final ActionModel actionModel;
12 |
13 | @override
14 | Widget build(BuildContext context) {
15 | return ElevatedButton(
16 | onPressed: actionModel.action,
17 | style: ElevatedButton.styleFrom(
18 | backgroundColor: Colors.white,
19 | shape: RoundedRectangleBorder(
20 | borderRadius: BorderRadius.circular(10),
21 | ),
22 | elevation: 0,
23 | minimumSize: const Size(0, 77),
24 | ),
25 | child: Text(
26 | actionModel.text,
27 | maxLines: 2,
28 | overflow: TextOverflow.ellipsis,
29 | style: const TextStyle(color: CRLoggerColors.primaryColor),
30 | ),
31 | );
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/lib/src/page/actions_and_values/widgets/value_notifier_item.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/cr_logger.dart';
2 | import 'package:cr_logger/src/res/styles.dart';
3 | import 'package:flutter/material.dart';
4 |
5 | class ValueNotifierItem extends StatelessWidget {
6 | const ValueNotifierItem({
7 | required this.notifierData,
8 | super.key,
9 | });
10 |
11 | final NotifierData notifierData;
12 |
13 | @override
14 | Widget build(BuildContext context) {
15 | final notifier = notifierData.valueNotifier;
16 |
17 | return notifier != null
18 | ? ValueListenableBuilder(
19 | valueListenable: notifier,
20 | //ignore: prefer-trailing-comma
21 | builder: (_, value, __) {
22 | return Row(
23 | children: [
24 | Expanded(
25 | child: Text(
26 | notifierData.name ?? '',
27 | style: CRStyle.bodyBlackRegular14,
28 | ),
29 | ),
30 | const SizedBox(width: 20),
31 | Expanded(
32 | child: GestureDetector(
33 | onLongPress: () => copyClipboard(
34 | context,
35 | value.toString(),
36 | ),
37 | child: Text(
38 | value.toString(),
39 | style: CRStyle.bodyBlackRegular14,
40 | ),
41 | ),
42 | ),
43 | ],
44 | );
45 | },
46 | )
47 | : notifierData.widget ?? const SizedBox();
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/lib/src/page/app_info_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/src/cr_logger.dart';
2 | import 'package:cr_logger/src/cr_logger_helper.dart';
3 | import 'package:cr_logger/src/page/widgets/app_info_item.dart';
4 | import 'package:cr_logger/src/res/colors.dart';
5 | import 'package:cr_logger/src/res/styles.dart';
6 | import 'package:cr_logger/src/widget/cr_app_bar.dart';
7 | import 'package:flutter/material.dart';
8 |
9 | class AppInfoPage extends StatelessWidget {
10 | const AppInfoPage({super.key});
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | final packageInfo = CRLoggerHelper.instance.packageInfo;
15 | final packageName = packageInfo.packageName;
16 | final version = packageInfo.version;
17 | final buildNumber = packageInfo.buildNumber;
18 | final customInfoItems = CRLoggerInitializer.instance.appInfo.entries;
19 |
20 | return Theme(
21 | data: CRLoggerHelper.instance.theme,
22 | child: Scaffold(
23 | backgroundColor: CRLoggerColors.backgroundGrey,
24 | appBar: const CRAppBar(title: 'App info'),
25 | body: ListView(
26 | padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 24),
27 | children: [
28 | /// Package name
29 | RichText(
30 | text: TextSpan(
31 | text: 'Package name: ',
32 | style: CRStyle.bodyBlackSemiBold14,
33 | children: [
34 | TextSpan(
35 | text: packageName,
36 | style: CRStyle.bodyBlackRegular14,
37 | ),
38 | ],
39 | ),
40 | ),
41 | const SizedBox(height: 12),
42 |
43 | /// Version
44 | RichText(
45 | textDirection: TextDirection.ltr,
46 | text: TextSpan(
47 | text: 'Version: ',
48 | style: CRStyle.bodyBlackSemiBold14,
49 | children: [
50 | TextSpan(
51 | text: '$version+$buildNumber',
52 | style: CRStyle.bodyBlackRegular14,
53 | ),
54 | ],
55 | ),
56 | ),
57 | const SizedBox(height: 6),
58 |
59 | /// Custom app info
60 | if (customInfoItems.isNotEmpty) ...[
61 | const Divider(),
62 | ...customInfoItems.map(
63 | (item) {
64 | return AppInfoItem(
65 | name: item.key,
66 | value: item.value,
67 | );
68 | },
69 | ).toList(),
70 | ],
71 | ],
72 | ),
73 | ),
74 | );
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/lib/src/page/log_main/log_main.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/cr_logger.dart';
2 | import 'package:cr_logger/src/cr_logger_helper.dart';
3 | import 'package:cr_logger/src/managers/log_manager.dart';
4 | import 'package:cr_logger/src/page/log_main/log_main_mobile.dart';
5 | import 'package:cr_logger/src/page/log_main/log_main_web.dart';
6 | import 'package:cr_logger/src/widget/adaptive_layout/adaptive_layout_widget.dart';
7 | import 'package:flutter/material.dart';
8 |
9 | class MainLogPage extends StatefulWidget {
10 | const MainLogPage({
11 | required this.navigationKey,
12 | required this.onLoggerClose,
13 | super.key,
14 | });
15 |
16 | final GlobalKey navigationKey;
17 | final VoidCallback onLoggerClose;
18 |
19 | static void cleanLogs() {
20 | cleanDebug();
21 | cleanError();
22 | cleanInfo();
23 | cleanHttpLogs();
24 | }
25 |
26 | static void cleanHttpLogs() {
27 | HttpLogManager.instance.cleanAllLogs();
28 | }
29 |
30 | static void cleanDebug() {
31 | LogManager.instance.cleanDebug();
32 | }
33 |
34 | static void cleanInfo() {
35 | LogManager.instance.cleanInfo();
36 | }
37 |
38 | static void cleanError() {
39 | LogManager.instance.cleanError();
40 | }
41 |
42 | @override
43 | _MainLogPageState createState() => _MainLogPageState();
44 | }
45 |
46 | class _MainLogPageState extends State {
47 | @override
48 | Widget build(BuildContext context) {
49 | return Theme(
50 | data: CRLoggerHelper.instance.theme,
51 | child: ValueListenableBuilder(
52 | valueListenable: CRLoggerHelper.instance.loggerShowingNotifier,
53 | // ignore: prefer-trailing-comma
54 | builder: (_, showLogger, __) => Offstage(
55 | offstage: !showLogger,
56 | child: Navigator(
57 | key: widget.navigationKey,
58 | onGenerateRoute: _onGenerateRoute,
59 | ),
60 | ),
61 | ),
62 | );
63 | }
64 |
65 | Route? _onGenerateRoute(RouteSettings settings) {
66 | return MaterialPageRoute(
67 | builder: (context) => AdaptiveLayoutWidget(
68 | mobileLayoutWidget: MainLogMobilePage(
69 | onLoggerClose: widget.onLoggerClose,
70 | ),
71 | webLayoutWidget: MainLogWebPage(
72 | onLoggerClose: widget.onLoggerClose,
73 | ),
74 | ),
75 | settings: settings,
76 | );
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/lib/src/page/log_main/widgets/cr_web_appbar_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/src/page/widgets/popup_menu.dart';
2 | import 'package:cr_logger/src/res/styles.dart';
3 | import 'package:flutter/material.dart';
4 |
5 | class CRWebAppBar extends StatelessWidget {
6 | const CRWebAppBar({
7 | required this.popupKey,
8 | required this.onLoggerClose,
9 | super.key,
10 | });
11 |
12 | final GlobalKey popupKey;
13 | final VoidCallback onLoggerClose;
14 |
15 | @override
16 | Widget build(BuildContext context) {
17 | return SizedBox(
18 | height: 68,
19 | child: Row(
20 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
21 | children: [
22 | PopupMenu(
23 | popupKey: popupKey,
24 | child: const Padding(
25 | padding: EdgeInsets.all(8),
26 | child: Row(
27 | children: [
28 | Icon(Icons.view_headline),
29 | SizedBox(width: 10),
30 | Padding(
31 | padding: EdgeInsets.only(top: 2),
32 | child: Text(
33 | 'Menu',
34 | style: CRStyle.subtitle1BlackSemiBold16,
35 | ),
36 | ),
37 | ],
38 | ),
39 | ),
40 | ),
41 | InkWell(
42 | onTap: onLoggerClose,
43 | child: const Padding(
44 | padding: EdgeInsets.all(8),
45 | child: Row(
46 | children: [
47 | Text(
48 | 'Close',
49 | style: CRStyle.subtitle1BlackSemiBold16,
50 | ),
51 | SizedBox(width: 10),
52 | Icon(Icons.close),
53 | ],
54 | ),
55 | ),
56 | ),
57 | ],
58 | ),
59 | );
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/lib/src/page/log_main/widgets/mobile_header_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/src/controllers/logs_mode.dart';
2 | import 'package:cr_logger/src/controllers/logs_mode_controller.dart';
3 | import 'package:cr_logger/src/res/colors.dart';
4 | import 'package:cr_logger/src/res/styles.dart';
5 | import 'package:flutter/material.dart';
6 |
7 | class MobileHeaderWidget extends StatelessWidget {
8 | const MobileHeaderWidget({
9 | required this.onClear,
10 | required this.onAllClear,
11 | super.key,
12 | });
13 |
14 | final VoidCallback onClear;
15 | final VoidCallback onAllClear;
16 |
17 | @override
18 | Widget build(BuildContext context) {
19 | return Row(
20 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
21 | children: [
22 | const Row(
23 | children: [
24 | SizedBox(width: 16),
25 | Text(
26 | 'Logs',
27 | style: CRStyle.subtitle1BlackSemiBold16,
28 | ),
29 | ],
30 | ),
31 | Row(
32 | children: [
33 | TextButton(
34 | onPressed: onClear,
35 | onLongPress: onAllClear,
36 | style: TextButton.styleFrom(
37 | minimumSize: const Size(0, 20),
38 | padding: const EdgeInsets.symmetric(
39 | vertical: 4,
40 | horizontal: 16,
41 | ),
42 | foregroundColor: CRLoggerColors.red,
43 | ),
44 | child: ValueListenableBuilder(
45 | valueListenable: LogsModeController.instance.logMode,
46 | //ignore: prefer-trailing-comma
47 | builder: (_, value, __) => Text(
48 | value == LogsMode.fromCurrentSession
49 | ? 'Clear logs'
50 | : 'Clear logs from DB',
51 | style: CRStyle.bodyRedMedium14,
52 | ),
53 | ),
54 | ),
55 | ],
56 | ),
57 | ],
58 | );
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/lib/src/page/log_main/widgets/web_header_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/src/res/colors.dart';
2 | import 'package:cr_logger/src/res/styles.dart';
3 | import 'package:flutter/material.dart';
4 |
5 | class WebHeaderWidget extends StatelessWidget {
6 | const WebHeaderWidget({
7 | required this.onClear,
8 | required this.onAllClear,
9 | super.key,
10 | });
11 |
12 | final VoidCallback onClear;
13 | final VoidCallback onAllClear;
14 |
15 | @override
16 | Widget build(BuildContext context) {
17 | return Row(
18 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
19 | children: [
20 | const Row(
21 | children: [
22 | SizedBox(width: 16),
23 | Text(
24 | 'Logs',
25 | style: CRStyle.h2BlackSemibold,
26 | ),
27 | ],
28 | ),
29 | Row(
30 | children: [
31 | TextButton(
32 | onPressed: onClear,
33 | onLongPress: onAllClear,
34 | style: TextButton.styleFrom(
35 | minimumSize: const Size(0, 20),
36 | padding: const EdgeInsets.symmetric(
37 | vertical: 4,
38 | horizontal: 16,
39 | ),
40 | foregroundColor: CRLoggerColors.red,
41 | ),
42 | child: const Text(
43 | 'Clear logs',
44 | style: CRStyle.subtitle1RedMedium16,
45 | ),
46 | ),
47 | ],
48 | ),
49 | ],
50 | );
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/lib/src/page/search/search_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/src/controllers/logs_mode.dart';
2 | import 'package:cr_logger/src/controllers/logs_mode_controller.dart';
3 | import 'package:cr_logger/src/cr_logger_helper.dart';
4 | import 'package:cr_logger/src/page/search/http_search_page.dart';
5 | import 'package:cr_logger/src/page/search/log_search_page.dart';
6 | import 'package:cr_logger/src/res/colors.dart';
7 | import 'package:cr_logger/src/res/styles.dart';
8 | import 'package:cr_logger/src/widget/cr_back_button.dart';
9 | import 'package:cr_logger/src/widget/options_buttons.dart';
10 | import 'package:flutter/material.dart';
11 |
12 | class SearchPage extends StatefulWidget {
13 | const SearchPage({super.key});
14 |
15 | @override
16 | _SearchPageState createState() => _SearchPageState();
17 | }
18 |
19 | class _SearchPageState extends State {
20 | final _searchCtrl = TextEditingController();
21 |
22 | final _pageController = PageController();
23 |
24 | final _logsMode = LogsModeController.instance.logMode.value;
25 |
26 | bool get _isCurrentLogMode => _logsMode == LogsMode.fromCurrentSession;
27 |
28 | @override
29 | void dispose() {
30 | _searchCtrl.dispose();
31 | _pageController.dispose();
32 | super.dispose();
33 | }
34 |
35 | @override
36 | Widget build(BuildContext context) => Theme(
37 | data: CRLoggerHelper.instance.theme,
38 | child: SafeArea(
39 | child: Scaffold(
40 | backgroundColor: CRLoggerColors.backgroundGrey,
41 | appBar: AppBar(
42 | centerTitle: true,
43 | elevation: 0,
44 | backgroundColor: CRLoggerColors.backgroundGrey,
45 |
46 | /// App bar title
47 | title: Text(
48 | _isCurrentLogMode ? 'Search in logs' : 'Search log in DB',
49 | style: CRStyle.subtitle1BlackSemiBold17,
50 | ),
51 | leading: const CRBackButton(),
52 |
53 | /// Tabs: HTTP and Logs
54 | bottom: PreferredSize(
55 | preferredSize: const Size(
56 | double.infinity,
57 | kToolbarHeight,
58 | ),
59 | child: Padding(
60 | padding: const EdgeInsets.only(
61 | top: 8,
62 | left: 16,
63 | right: 16,
64 | bottom: 14,
65 | ),
66 | child: OptionsButtons(
67 | titles: const ['HTTP', 'Logs'],
68 | onSelected: _onChangedTab,
69 | ),
70 | ),
71 | ),
72 | ),
73 | body: Column(
74 | children: [
75 | /// Correct page dependens on the tab. HTTP page or Logs page
76 | Expanded(
77 | child: PageView(
78 | physics: const NeverScrollableScrollPhysics(),
79 | controller: _pageController,
80 | children: const [
81 | HttpSearchPage(),
82 | LogSearchPage(),
83 | ],
84 | ),
85 | ),
86 | ],
87 | ),
88 | ),
89 | ),
90 | );
91 |
92 | void _onChangedTab(int index) {
93 | _pageController.jumpToPage(index);
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/lib/src/page/search/widgets/path_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/src/res/colors.dart';
2 | import 'package:cr_logger/src/res/styles.dart';
3 | import 'package:flutter/material.dart';
4 |
5 | class PathWidget extends StatelessWidget {
6 | const PathWidget({
7 | required this.onSearchUrl,
8 | required this.path,
9 | super.key,
10 | });
11 |
12 | final VoidCallback onSearchUrl;
13 | final String path;
14 |
15 | @override
16 | Widget build(BuildContext context) {
17 | return GestureDetector(
18 | onTap: onSearchUrl,
19 | child: Container(
20 | margin: const EdgeInsets.all(2),
21 | padding: const EdgeInsets.all(8),
22 | decoration: BoxDecoration(
23 | borderRadius: BorderRadius.circular(16),
24 | border: Border.all(
25 | color: CRLoggerColors.progressBackground,
26 | ),
27 | color: CRLoggerColors.white,
28 | ),
29 | child: Text(
30 | path,
31 | style: CRStyle.bodyBlackSemiDefault13,
32 | ),
33 | ),
34 | );
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/lib/src/page/widgets/app_info_item.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/src/res/styles.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | class AppInfoItem extends StatelessWidget {
5 | const AppInfoItem({
6 | required this.name,
7 | required this.value,
8 | super.key,
9 | });
10 |
11 | final String name;
12 | final String value;
13 |
14 | @override
15 | Widget build(BuildContext context) {
16 | return Padding(
17 | padding: const EdgeInsets.symmetric(vertical: 6),
18 | child: Column(
19 | crossAxisAlignment: CrossAxisAlignment.start,
20 | children: [
21 | Text(name, style: CRStyle.bodyBlackSemiBold14),
22 | Padding(
23 | padding: const EdgeInsets.only(left: 14, top: 6),
24 | child: Text(value, style: CRStyle.bodyBlackRegular14),
25 | ),
26 | ],
27 | ),
28 | );
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/lib/src/page/widgets/clear_logs_content_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/src/res/colors.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | class ClearLogsContentWidget extends StatefulWidget {
5 | const ClearLogsContentWidget({
6 | required this.clearLogsFromDB,
7 | super.key,
8 | });
9 |
10 | final ValueChanged clearLogsFromDB;
11 |
12 | @override
13 | State createState() => _ClearLogsContentWidgetState();
14 | }
15 |
16 | class _ClearLogsContentWidgetState extends State {
17 | bool _clearLogsFromDB = false;
18 |
19 | @override
20 | Widget build(BuildContext context) {
21 | return Column(
22 | crossAxisAlignment: CrossAxisAlignment.start,
23 | mainAxisSize: MainAxisSize.min,
24 | children: [
25 | const Text('Do you want to clear all logs?'),
26 | const SizedBox(height: 4),
27 | CheckboxListTile(
28 | contentPadding: const EdgeInsets.only(left: 2),
29 | activeColor: CRLoggerColors.blue,
30 | value: _clearLogsFromDB,
31 | onChanged: _onChanged,
32 | title: const Text(
33 | 'Clear the database',
34 | style: TextStyle(fontSize: 14),
35 | ),
36 | ),
37 | ],
38 | );
39 | }
40 |
41 | void _onChanged(bool? value) {
42 | if (value != null) {
43 | setState(() {
44 | _clearLogsFromDB = value;
45 | });
46 | widget.clearLogsFromDB(_clearLogsFromDB);
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/lib/src/page/widgets/cupertino_search_field.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/src/res/colors.dart';
2 | import 'package:flutter/cupertino.dart';
3 | import 'package:flutter/material.dart';
4 |
5 | class CupertinoSearchField extends StatefulWidget {
6 | const CupertinoSearchField({
7 | required this.searchController,
8 | required this.onSearch,
9 | required this.onClear,
10 | required this.placeholderText,
11 | super.key,
12 | });
13 |
14 | final TextEditingController searchController;
15 | final VoidCallback onSearch;
16 | final VoidCallback onClear;
17 | final String placeholderText;
18 |
19 | @override
20 | State createState() => _CupertinoSearchFieldState();
21 | }
22 |
23 | class _CupertinoSearchFieldState extends State {
24 | final _focusNode = FocusNode();
25 |
26 | @override
27 | void dispose() {
28 | _focusNode.dispose();
29 | super.dispose();
30 | }
31 |
32 | @override
33 | Widget build(BuildContext context) {
34 | return Padding(
35 | padding: const EdgeInsets.symmetric(horizontal: 16),
36 | child: Row(
37 | children: [
38 | /// Cupertino search field
39 | Expanded(
40 | child: CupertinoTextField(
41 | focusNode: _focusNode,
42 | controller: widget.searchController,
43 | padding: const EdgeInsets.symmetric(
44 | vertical: 8,
45 | horizontal: 12,
46 | ),
47 | onChanged: (_) => widget.onSearch(),
48 | suffixMode: OverlayVisibilityMode.editing,
49 | suffix: IconButton(
50 | padding: EdgeInsets.zero,
51 | onPressed: widget.onClear,
52 | icon: const Icon(Icons.clear),
53 | ),
54 | placeholder: widget.placeholderText,
55 | cursorWidth: 1,
56 | cursorColor: CRLoggerColors.primaryColor,
57 | decoration: BoxDecoration(
58 | color: CRLoggerColors.white,
59 | borderRadius: BorderRadius.circular(21),
60 | ),
61 | ),
62 | ),
63 | ],
64 | ),
65 | );
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/lib/src/page/widgets/json_details_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/src/res/styles.dart';
2 | import 'package:cr_logger/src/widget/expand_arrow_button.dart';
3 | import 'package:cr_logger/src/widget/json_widget/json_widget.dart';
4 | import 'package:flutter/material.dart';
5 |
6 | class JsonDetailsWidget extends StatefulWidget {
7 | const JsonDetailsWidget({
8 | required this.logMessage,
9 | super.key,
10 | });
11 |
12 | final Map logMessage;
13 |
14 | @override
15 | State createState() => _JsonDetailsWidgetState();
16 | }
17 |
18 | class _JsonDetailsWidgetState extends State {
19 | final _allExpandedNodesNotifier = ValueNotifier(true);
20 |
21 | @override
22 | void dispose() {
23 | _allExpandedNodesNotifier.dispose();
24 |
25 | super.dispose();
26 | }
27 |
28 | @override
29 | Widget build(BuildContext context) {
30 | return ValueListenableBuilder(
31 | valueListenable: _allExpandedNodesNotifier,
32 | builder: (
33 | BuildContext context,
34 | bool isAllNodesExpanded,
35 | Widget? child,
36 | ) {
37 | return Column(
38 | children: [
39 | Row(
40 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
41 | children: [
42 | /// Json title
43 | const Text(
44 | 'JSON data',
45 | style: CRStyle.subtitle1BlackSemiBold16,
46 | ),
47 |
48 | /// Json expand button
49 | ExpandArrowButton(
50 | isExpanded: isAllNodesExpanded,
51 | onTap: _onExpandArrowTap,
52 | ),
53 | ],
54 | ),
55 |
56 | /// Json widget
57 | JsonWidget(
58 | widget.logMessage,
59 | allExpandedNodes: isAllNodesExpanded,
60 | ),
61 | ],
62 | );
63 | },
64 | );
65 | }
66 |
67 | void _onExpandArrowTap() {
68 | _allExpandedNodesNotifier.value = !_allExpandedNodesNotifier.value;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/lib/src/page/widgets/progress_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/src/res/colors.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | class ProgressWidget extends StatelessWidget {
5 | const ProgressWidget({super.key});
6 |
7 | @override
8 | Widget build(BuildContext context) {
9 | return Container(
10 | alignment: Alignment.center,
11 | color: CRLoggerColors.backgroundGrey.withOpacity(0.8),
12 | child: const CircularProgressIndicator(strokeWidth: 2),
13 | );
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/lib/src/providers/sqflite_provider.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/cr_logger.dart';
2 | import 'package:cr_logger/src/data/sqflite_db/log_module.dart';
3 |
4 | final class SqfliteProvider {
5 | SqfliteProvider._();
6 |
7 | static final instance = SqfliteProvider._();
8 |
9 | final _module = LogModule.instance;
10 |
11 | Future init() => _module.init();
12 |
13 | /// HTTP logs
14 | Future saveHttpLog(HttpBean httpLog) => _module.saveHttpLog(httpLog);
15 |
16 | Future updateHttpLog(HttpBean httpLog) =>
17 | _module.updateHttpLog(httpLog);
18 |
19 | Future> getAllSavedHttpLogs() => _module.getAllSavedHttpLogs();
20 |
21 | Future deleteAllHttpLogs() => _module.deleteAllHttpLogs();
22 |
23 | Future deleteHttpLogs(List logs) =>
24 | _module.deleteHttpLogs(logs);
25 |
26 | /// Logs
27 | Future saveLog(LogBean log) => _module.saveLog(log);
28 |
29 | Future> getAllSavedLogs() => _module.getAllSavedLogs();
30 |
31 | Future deleteAllLogs() => _module.deleteAllLogs();
32 |
33 | Future deleteLogs(List logs) => _module.deleteLogs(logs);
34 | }
35 |
--------------------------------------------------------------------------------
/lib/src/res/colors.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | final class CRLoggerColors {
4 | CRLoggerColors._();
5 |
6 | static const primaryColor = Color(0xFF151923);
7 | static const accentColor = Color(0xffff9f00);
8 | static const black = Colors.black;
9 | static const white = Colors.white;
10 | static const whitish = Color(0xFFDADCE0);
11 | static const grey = Color(0xFF77788A);
12 | static const orange = Color(0xFFDE5507);
13 | static const red = Color(0xFFDF3731);
14 | static const blue = Color(0xFF1B6CFF);
15 | static const darkMagenta = Color(0xFFBB5BC3);
16 | static const blueAccent = Color(0xFF0980C2);
17 | static const lightRed = Color(0xFFFCC6C2);
18 | static const linkBlue = Color(0xFFABCAFF);
19 | static const linkColor = Color(0xFFBB5BC3);
20 | static const green = Color(0xFF199B4D);
21 | static const greenAccent = Color(0xFF1EB35D);
22 | static const progressBackground = Color(0xFFB8C7CB);
23 | static const backgroundGrey = Color(0xFFF3F5F6);
24 |
25 | static const yellow = Colors.orangeAccent;
26 |
27 | static Brightness brightness = Brightness.dark;
28 | }
29 |
--------------------------------------------------------------------------------
/lib/src/res/theme.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/src/res/colors.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | ThemeData get loggerTheme => ThemeData(
5 | primaryColor: CRLoggerColors.primaryColor,
6 | brightness: Brightness.light,
7 | indicatorColor: CRLoggerColors.accentColor,
8 | iconTheme: const IconThemeData(
9 | color: CRLoggerColors.primaryColor,
10 | ),
11 | textSelectionTheme: const TextSelectionThemeData(
12 | cursorColor: CRLoggerColors.black,
13 | ),
14 | dialogTheme: const DialogTheme(
15 | backgroundColor: Colors.white,
16 | contentTextStyle: TextStyle(
17 | color: Colors.black87,
18 | fontSize: 16,
19 | ),
20 | titleTextStyle: TextStyle(
21 | color: Colors.black,
22 | fontSize: 18,
23 | fontWeight: FontWeight.w600,
24 | ),
25 | shape: Border(),
26 | ),
27 | cardTheme: CardTheme(
28 | shape: RoundedRectangleBorder(
29 | borderRadius: BorderRadius.circular(4),
30 | ),
31 | elevation: 6,
32 | ),
33 | appBarTheme: const AppBarTheme(
34 | backgroundColor: CRLoggerColors.backgroundGrey,
35 | elevation: 0,
36 | ),
37 | canvasColor: CRLoggerColors.white,
38 | popupMenuTheme: const PopupMenuThemeData(color: CRLoggerColors.white),
39 | colorScheme: ColorScheme.fromSwatch().copyWith(
40 | secondary: CRLoggerColors.accentColor,
41 | onSecondary: CRLoggerColors.primaryColor,
42 | ),
43 | scaffoldBackgroundColor: CRLoggerColors.backgroundGrey,
44 | fontFamily: 'Epilogue',
45 | );
46 |
--------------------------------------------------------------------------------
/lib/src/utils/console_log_output.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/src/constants.dart';
2 | import 'package:cr_logger/src/cr_logger_helper.dart';
3 | import 'package:cr_logger/src/js/console_output_worker.dart';
4 | import 'package:cr_logger/src/js/scripts.dart';
5 | import 'package:cr_logger/src/utils/html_stub.dart'
6 | if (dart.library.js) 'dart:html' as html;
7 | import 'package:flutter/foundation.dart';
8 | import 'package:logger/logger.dart';
9 | import 'package:worker_manager/worker_manager.dart';
10 |
11 | final class ConsoleLogOutput extends LogOutput {
12 | ConsoleLogOutput() {
13 | if (kIsWeb) {
14 | _createWorker();
15 | }
16 | }
17 |
18 | @override
19 | Future output(OutputEvent event) async {
20 | await CRLoggerHelper.instance.lock.synchronized(() async {
21 | if (kIsWeb) {
22 | if (kReleaseMode || kProfileMode) {
23 | final src = html.ScriptElement()..text = printLogsScript;
24 | html.document.body?.append(src);
25 | printLogs(event.lines);
26 | src.remove();
27 | } else {
28 | // ignore: avoid_print
29 | event.lines.forEach(print);
30 | }
31 | } else {
32 | await workerManager.execute(() async => isolatePrintLog(event.lines));
33 | }
34 | });
35 | }
36 |
37 | void _createWorker() {
38 | final srcWorker = html.ScriptElement()
39 | ..id = kWorkerId
40 | ..text = workerScript;
41 | html.document.body?.append(srcWorker);
42 | final srcCreateWorker = html.ScriptElement()..text = createWorkerScript;
43 | html.document.body?.append(srcCreateWorker);
44 | }
45 | }
46 |
47 | Object isolatePrintLog(dynamic data) {
48 | if (data is List) {
49 | // ignore: avoid_print
50 | data.forEach(print);
51 | }
52 |
53 | return '';
54 | }
55 |
--------------------------------------------------------------------------------
/lib/src/utils/copy_clipboard.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter/services.dart';
3 |
4 | void copyClipboard(
5 | BuildContext context,
6 | String value, {
7 | Color selectValueColor = Colors.white,
8 | }) {
9 | final snackBar = SnackBar(
10 | content: RichText(
11 | overflow: TextOverflow.ellipsis,
12 | maxLines: 4,
13 | text: TextSpan(
14 | children: [
15 | const TextSpan(text: 'Copy '),
16 | TextSpan(
17 | text: '"$value"',
18 | style: TextStyle(
19 | color: selectValueColor,
20 | ),
21 | ),
22 | const TextSpan(text: ' to clipboard'),
23 | ],
24 | ),
25 | ),
26 | );
27 | ScaffoldMessenger.of(context).clearSnackBars();
28 | ScaffoldMessenger.of(context).showSnackBar(snackBar);
29 | Clipboard.setData(ClipboardData(text: value));
30 | }
31 |
--------------------------------------------------------------------------------
/lib/src/utils/enum_ext.dart:
--------------------------------------------------------------------------------
1 | extension EnumValueOf on Iterable {
2 | T? valueOf(String? name) {
3 | if (name != null) {
4 | final lowerCase = name.toLowerCase();
5 |
6 | return firstWhere((value) => value.name == lowerCase);
7 | }
8 |
9 | return null;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/lib/src/utils/hide_values_in_map.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/cr_logger.dart';
2 | import 'package:cr_logger/src/constants.dart';
3 |
4 | Map hideValuesInMap(Map body) {
5 | return body.map((key, value) {
6 | if (CRLoggerInitializer.instance.hiddenFields.contains(key)) {
7 | return MapEntry(key, kHidden);
8 | } else {
9 | if (value is Map) {
10 | return MapEntry(key, hideValuesInMap(value));
11 | }
12 | if (value is List) {
13 | final list = value.map((e) {
14 | return e is Map ? hideValuesInMap(e) : e;
15 | }).toList();
16 |
17 | return MapEntry(key, list);
18 | }
19 |
20 | return MapEntry(key, value);
21 | }
22 | });
23 | }
24 |
--------------------------------------------------------------------------------
/lib/src/utils/html_stub.dart:
--------------------------------------------------------------------------------
1 | final class ScriptElement {
2 | late String text;
3 | late String id;
4 | late bool defer;
5 |
6 | // ignore: no-empty-block
7 | void remove() {}
8 | }
9 |
10 | late DocStub document;
11 |
12 | final class DocStub {
13 | BodyStub? body;
14 | }
15 |
16 | class BodyStub {
17 | // ignore: avoid-unused-parameters
18 | // ignore: no-empty-block
19 | void append(_) {}
20 | }
21 |
22 | final class JS {
23 | const JS([this.name]);
24 |
25 | final String? name;
26 | }
27 |
--------------------------------------------------------------------------------
/lib/src/utils/json_utils.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 |
3 | String toJson(Object? data) {
4 | const je = JsonEncoder.withIndent(' ');
5 | final json = je.convert(data);
6 |
7 | return json;
8 | }
9 |
--------------------------------------------------------------------------------
/lib/src/utils/map_ext.dart:
--------------------------------------------------------------------------------
1 | extension MapExt on Map {
2 | // ignore: avoid_annotating_with_dynamic
3 | void putIfNotNull(dynamic value, T key) {
4 | if (value != null) {
5 | this[key] = value;
6 | }
7 | }
8 |
9 | void clearAllNull() {
10 | removeWhere((key, value) => value == null);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/lib/src/utils/nothing_log_filter.dart:
--------------------------------------------------------------------------------
1 | import 'package:logger/logger.dart';
2 |
3 | final class NothingLogFilter extends LogFilter {
4 | @override
5 | bool shouldLog(LogEvent event) {
6 | return false;
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/lib/src/utils/pair.dart:
--------------------------------------------------------------------------------
1 | final class Pair {
2 | Pair({
3 | required this.first,
4 | required this.second,
5 | });
6 |
7 | final A first;
8 | final B second;
9 | }
10 |
--------------------------------------------------------------------------------
/lib/src/utils/paramas_detector/parameter_model.dart:
--------------------------------------------------------------------------------
1 | final class ParameterModel {
2 | ParameterModel({
3 | required this.name,
4 | required this.locationStart,
5 | required this.locationEnd,
6 | });
7 |
8 | final int locationStart;
9 | final int locationEnd;
10 | final String name;
11 | }
12 |
--------------------------------------------------------------------------------
/lib/src/utils/paramas_detector/params_detector.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/src/constants.dart';
2 | import 'package:cr_logger/src/utils/paramas_detector/parameter_model.dart';
3 |
4 | final class ParameterDetector {
5 | static final _parameterRegex = RegExp(r'\{\{[^{}]+\}\}');
6 |
7 | List getParams(String text) {
8 | final params = [];
9 |
10 | if (_parameterRegex.hasMatch(text)) {
11 | final matches = _parameterRegex.allMatches(text);
12 | if (matches.isNotEmpty) {
13 | for (final match in matches) {
14 | final param = match.group(0);
15 | if (param != null) {
16 | params.add(
17 | ParameterModel(
18 | name: param.replaceAll(patternOfParamsRegex, ''),
19 | locationStart: match.start,
20 | locationEnd: match.end,
21 | ),
22 | );
23 | }
24 | }
25 | }
26 | }
27 |
28 | return params;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/lib/src/utils/parsers/isolate_parser.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 |
3 | import 'package:worker_manager/worker_manager.dart';
4 |
5 | /// This class is for converting a [String] into a [Map] and conversely.
6 | final class IsolateParser {
7 | /// [data] is a string, but may contain a map, so a decoding attempt is made first. If it fails, [data] is returned as a string.
8 | dynamic decode(String data) =>
9 | workerManager.execute(() async => _decode(data));
10 |
11 | /// [data] can be any type, so there is a check if it is a map, then [json.encode] is called,
12 | /// otherwise [data] is converted into a string and returned.
13 | Future encode(dynamic data) =>
14 | workerManager.execute(() async => _encode(data));
15 | }
16 |
17 | dynamic _decode(String data) {
18 | try {
19 | return json.decode(data);
20 | } catch (_) {
21 | return Future.value(data);
22 | }
23 | }
24 |
25 | String _encode(dynamic data) =>
26 | data is Map ? json.encode(data) : data.toString();
27 |
--------------------------------------------------------------------------------
/lib/src/utils/parsers/url_parser.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/cr_logger.dart';
2 |
3 | String getUrlWithHiddenParams(String url, {bool showFullPath = false}) {
4 | final uri = Uri.tryParse(url);
5 |
6 | /// Get path without scheme.
7 | /// E.g. httpbin/anything instead of https://httpbin/anything
8 | final absolutePath = '${uri?.host}${uri?.path}';
9 |
10 | /// Get all parameters
11 | final parameters = uri?.queryParameters;
12 |
13 | /// Separate the base url and parameters to avoid replacing parts of the base url
14 | final resultUrl = url.split('?');
15 |
16 | if (!showFullPath) {
17 | resultUrl.first = absolutePath;
18 | }
19 |
20 | /// If there is no parameters then nothing to hide and just return url
21 | if (resultUrl.length < 2) {
22 | return resultUrl.join();
23 | }
24 |
25 | /// Replace
26 | CRLoggerInitializer.instance.hiddenFields.forEach((element) {
27 | final value = parameters?[element];
28 | if (value != null) {
29 | /// = needed to avoid replacing keys if parameter have the same name as key
30 | ///
31 | /// E.g. https://....?test=test
32 | resultUrl[1] = resultUrl[1].replaceAll('=$value', '=...');
33 | }
34 | });
35 |
36 | return resultUrl.join('?');
37 | }
38 |
--------------------------------------------------------------------------------
/lib/src/utils/show_info_dialog.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/src/cr_logger_helper.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | Future showInfoDialog({
5 | required BuildContext context,
6 | Widget? title,
7 | Widget? content,
8 | }) =>
9 | showDialog(
10 | context: context,
11 | builder: (context) => Theme(
12 | data: CRLoggerHelper.instance.theme,
13 | child: AlertDialog(
14 | title: title,
15 | content: content,
16 | actions: [
17 | TextButton(
18 | onPressed: () => Navigator.pop(context),
19 | child: const Text('CLOSE'),
20 | ),
21 | ],
22 | ),
23 | ),
24 | );
25 |
--------------------------------------------------------------------------------
/lib/src/utils/show_log_snack_bar.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | /// Displays the snack bar when a log is added with the snack bar display option
4 | /// Pressing the "OPEN" button opens the logger, the tab in which the log
5 | /// belongs and the log details page
6 | void showLogSnackBar(
7 | ScaffoldMessengerState scaffoldMessengerState,
8 | VoidCallback? onOpen,
9 | String message,
10 | ) {
11 | final scaffold = scaffoldMessengerState;
12 | scaffold
13 | ..hideCurrentSnackBar()
14 | ..showSnackBar(
15 | SnackBar(
16 | content: Text(
17 | 'Log: $message',
18 | maxLines: 1,
19 | overflow: TextOverflow.ellipsis,
20 | ),
21 | action: SnackBarAction(
22 | label: 'OPEN',
23 | textColor: Colors.green,
24 | //ignore:prefer-extracting-callbacks
25 | onPressed: () {
26 | scaffold.hideCurrentSnackBar();
27 | onOpen?.call();
28 | },
29 | ),
30 | ),
31 | );
32 | }
33 |
--------------------------------------------------------------------------------
/lib/src/utils/show_remove_log_bottom_sheet.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/src/utils/web_utils.dart';
2 | import 'package:cr_logger/src/widget/delete_log_confirm_widget.dart';
3 | import 'package:flutter/material.dart';
4 |
5 | Future showRemoveLogBottomSheet(
6 | BuildContext context, {
7 | required String message,
8 | final Color textColor = Colors.black,
9 | }) async {
10 | final bottomSheetWidth =
11 | MediaQuery.of(context).size.width > kWidthTrashHoldForMobileLayout
12 | ? 400.0
13 | : double.infinity;
14 |
15 | final result = await showModalBottomSheet(
16 | context: context,
17 | shape: const RoundedRectangleBorder(
18 | borderRadius: BorderRadius.only(
19 | topRight: Radius.circular(20),
20 | topLeft: Radius.circular(20),
21 | ),
22 | ),
23 | constraints: BoxConstraints(maxWidth: bottomSheetWidth),
24 | builder: (context) => DeleteLogConfirmWidget(
25 | message: message,
26 | textColor: textColor,
27 | ),
28 | );
29 |
30 | return result == DeleteLogConfirmation.ok;
31 | }
32 |
--------------------------------------------------------------------------------
/lib/src/utils/show_remove_log_snack_bar.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | /// Displays the snack bar after deleting the log
4 | /// Pressing the "UNDO" button restores the deleted log
5 | void showRemoveLogSnackBar(BuildContext context, VoidCallback? onUndo) {
6 | final scaffold = ScaffoldMessenger.of(context);
7 | scaffold
8 | ..hideCurrentSnackBar()
9 | ..showSnackBar(
10 | SnackBar(
11 | content: const Text(
12 | 'Log has been deleted',
13 | maxLines: 1,
14 | overflow: TextOverflow.ellipsis,
15 | ),
16 | action: SnackBarAction(
17 | label: 'UNDO',
18 | textColor: Colors.green,
19 | //ignore:prefer-extracting-callbacks
20 | onPressed: () {
21 | scaffold.hideCurrentSnackBar();
22 | onUndo?.call();
23 | },
24 | ),
25 | ),
26 | );
27 | }
28 |
--------------------------------------------------------------------------------
/lib/src/utils/unfocus.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | void unfocus() => WidgetsBinding.instance.focusManager.primaryFocus?.unfocus();
4 |
--------------------------------------------------------------------------------
/lib/src/utils/web_utils.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/foundation.dart';
2 |
3 | const double kMaxWebContentWidth = 1264;
4 |
5 | const double kDefaultDesktopWebContentWidth = 500;
6 |
7 | const double kWidthTrashHoldForMobileLayout = 1100;
8 |
9 | final kIsWebMobile = kIsWeb &&
10 | (defaultTargetPlatform == TargetPlatform.iOS ||
11 | defaultTargetPlatform == TargetPlatform.android);
12 |
13 | final kUserMobileLayoutForWeb = !kIsWeb || kIsWebMobile;
14 |
--------------------------------------------------------------------------------
/lib/src/widget/adaptive_layout/adaptive_layout_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/src/utils/web_utils.dart';
2 | import 'package:cr_logger/src/widget/adaptive_layout/layout_types.dart';
3 | import 'package:flutter/material.dart';
4 |
5 | class AdaptiveLayoutWidget extends StatefulWidget {
6 | const AdaptiveLayoutWidget({
7 | required this.mobileLayoutWidget,
8 | required this.webLayoutWidget,
9 | this.onLayoutChange,
10 | super.key,
11 | });
12 |
13 | final Widget mobileLayoutWidget;
14 | final Widget webLayoutWidget;
15 | final ValueChanged? onLayoutChange;
16 |
17 | @override
18 | _AdaptiveLayoutWidgetState createState() => _AdaptiveLayoutWidgetState();
19 | }
20 |
21 | class _AdaptiveLayoutWidgetState extends State {
22 | LayoutType _layoutType = LayoutType.web;
23 |
24 | @override
25 | Widget build(BuildContext context) {
26 | return LayoutBuilder(
27 | builder: (ctx, constraints) {
28 | final layoutType = _getLayoutTypeFromConstraints(constraints);
29 |
30 | // Use callback only when layout changed.
31 | if (_layoutType != layoutType) {
32 | _layoutType = layoutType;
33 | widget.onLayoutChange?.call(_layoutType);
34 | }
35 |
36 | return _layoutType.isWebLayout
37 | ? widget.webLayoutWidget
38 | : widget.mobileLayoutWidget;
39 | },
40 | );
41 | }
42 |
43 | LayoutType _getLayoutTypeFromConstraints(BoxConstraints constraints) {
44 | return constraints.maxWidth > kWidthTrashHoldForMobileLayout
45 | ? LayoutType.web
46 | : LayoutType.mobile;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/lib/src/widget/adaptive_layout/layout_types.dart:
--------------------------------------------------------------------------------
1 | enum LayoutType {
2 | web,
3 | mobile,
4 | }
5 |
6 | extension LayoutTypeExt on LayoutType {
7 | bool get isWebLayout => this == LayoutType.web;
8 | }
9 |
--------------------------------------------------------------------------------
/lib/src/widget/body_expansion_tile.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/cr_logger.dart';
2 | import 'package:cr_logger/src/res/colors.dart';
3 | import 'package:cr_logger/src/res/styles.dart';
4 | import 'package:cr_logger/src/widget/expand_arrow_button.dart';
5 | import 'package:cr_logger/src/widget/json_widget/json_widget.dart';
6 | import 'package:cr_logger/src/widget/rounded_card.dart';
7 | import 'package:dio/dio.dart';
8 | import 'package:flutter/material.dart';
9 |
10 | class BodyExpansionTile extends StatefulWidget {
11 | const BodyExpansionTile({
12 | required this.request,
13 | super.key,
14 | });
15 |
16 | final RequestBean? request;
17 |
18 | @override
19 | State createState() => _BodyExpansionTileState();
20 | }
21 |
22 | class _BodyExpansionTileState extends State {
23 | bool _isExpanded = false;
24 |
25 | @override
26 | Widget build(BuildContext context) {
27 | const _jsonWidgetBodyValueKey = ValueKey('RequestPageBody');
28 | final bodyIsString = widget.request?.body is String;
29 | final bodyLength =
30 | bodyIsString ? 1 : _tryGetBodyAsMap(widget.request)?.length ?? 0;
31 | final bodyIsNotEmpty = bodyLength != 0;
32 |
33 | return RoundedCard(
34 | padding: const EdgeInsets.only(
35 | left: 16,
36 | top: 10,
37 | right: 16,
38 | bottom: 10,
39 | ),
40 | child: Column(
41 | children: [
42 | Row(
43 | children: [
44 | const Expanded(
45 | child: Text(
46 | 'Body',
47 | style: CRStyle.subtitle1BlackSemiBold16,
48 | ),
49 | ),
50 | Text(
51 | '$bodyLength',
52 | style: CRStyle.subtitle1BlackSemiBold16.copyWith(
53 | color: CRLoggerColors.grey,
54 | ),
55 | ),
56 | const SizedBox(width: 6),
57 | ExpandArrowButton(
58 | isExpanded: _isExpanded && bodyIsNotEmpty,
59 | onTap: bodyIsNotEmpty ? _expand : null,
60 | ),
61 | ],
62 | ),
63 | if (bodyIsNotEmpty && !bodyIsString)
64 | JsonWidget(
65 | _tryGetBodyAsMap(widget.request),
66 | allExpandedNodes: _isExpanded,
67 | key: _jsonWidgetBodyValueKey,
68 | ),
69 | if (bodyIsString && _isExpanded) Text(widget.request?.body),
70 | ],
71 | ),
72 | );
73 | }
74 |
75 | Map? _tryGetBodyAsMap(request) {
76 | if (request?.body is FormData) {
77 | return request?.getFormData() ?? '';
78 | } else if (request?.body is List) {
79 | return request?.body ?? '';
80 | } else if (request?.body is Map) {
81 | return request?.body ?? '';
82 | } else {
83 | return null;
84 | }
85 | }
86 |
87 | void _expand() => setState(() => _isExpanded = !_isExpanded);
88 | }
89 |
--------------------------------------------------------------------------------
/lib/src/widget/build_number.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:package_info_plus/package_info_plus.dart';
3 |
4 | class BuildNumber extends StatelessWidget {
5 | const BuildNumber({super.key});
6 |
7 | @override
8 | Widget build(BuildContext context) {
9 | return Material(
10 | type: MaterialType.transparency,
11 | child: FutureBuilder(
12 | future: PackageInfo.fromPlatform(),
13 | builder: (
14 | BuildContext context,
15 | AsyncSnapshot snapshot,
16 | ) {
17 | final buildNumber =
18 | snapshot.hasData ? snapshot.data?.buildNumber : null;
19 |
20 | return Text(
21 | buildNumber ?? '',
22 | style: const TextStyle(
23 | fontSize: 18,
24 | fontWeight: FontWeight.normal,
25 | color: Colors.white,
26 | ),
27 | );
28 | },
29 | ),
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/lib/src/widget/copy_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/generated/assets.dart';
2 | import 'package:cr_logger/src/extensions/extensions.dart';
3 | import 'package:flutter/material.dart';
4 |
5 | class CopyWidget extends StatelessWidget {
6 | const CopyWidget({
7 | required this.onCopy,
8 | super.key,
9 | });
10 |
11 | final VoidCallback? onCopy;
12 |
13 | @override
14 | Widget build(BuildContext context) {
15 | return SizedBox.square(
16 | dimension: 28,
17 | child: IconButton(
18 | onPressed: onCopy,
19 | icon: ImageExt.fromPackage(
20 | CRLoggerAssets.assetsContentCopy,
21 | height: 20,
22 | width: 20,
23 | ),
24 | iconSize: 20,
25 | splashRadius: 20,
26 | padding: EdgeInsets.zero,
27 | ),
28 | );
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/lib/src/widget/cr_app_bar.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/src/res/colors.dart';
2 | import 'package:cr_logger/src/res/styles.dart';
3 | import 'package:cr_logger/src/widget/cr_back_button.dart';
4 | import 'package:flutter/material.dart';
5 |
6 | class CRAppBar extends StatelessWidget implements PreferredSizeWidget {
7 | const CRAppBar({
8 | this.title = '',
9 | this.titleWidget,
10 | this.showBackButton,
11 | this.backButtonColor,
12 | this.onBackPressed,
13 | this.actions,
14 | this.reverse = false,
15 | this.centerTitle = true,
16 | super.key,
17 | });
18 |
19 | final String title;
20 | final Widget? titleWidget;
21 | final bool centerTitle;
22 | final bool reverse;
23 | final bool? showBackButton;
24 | final Color? backButtonColor;
25 | final VoidCallback? onBackPressed;
26 | final List? actions;
27 |
28 | @override
29 | Size get preferredSize => const Size.fromHeight(kToolbarHeight);
30 |
31 | @override
32 | Widget build(BuildContext context) => AppBar(
33 | centerTitle: centerTitle,
34 | automaticallyImplyLeading: false,
35 | leading: CRBackButton(
36 | color: backButtonColor,
37 | showBackButton: showBackButton,
38 | onPressed: onBackPressed,
39 | ),
40 | title: titleWidget ??
41 | Text(
42 | title,
43 | style: CRStyle.subtitle1BlackSemiBold17,
44 | ),
45 | elevation: 0,
46 | backgroundColor: CRLoggerColors.backgroundGrey,
47 | actions: actions,
48 | );
49 | }
50 |
--------------------------------------------------------------------------------
/lib/src/widget/cr_back_button.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/generated/assets.dart';
2 | import 'package:cr_logger/src/extensions/image_ext.dart';
3 | import 'package:flutter/material.dart';
4 |
5 | class CRBackButton extends StatelessWidget {
6 | const CRBackButton({
7 | super.key,
8 | this.color,
9 | this.onPressed,
10 | this.showBackButton,
11 | });
12 |
13 | final bool? showBackButton;
14 | final Color? color;
15 | final VoidCallback? onPressed;
16 |
17 | @override
18 | Widget build(BuildContext context) {
19 | return (showBackButton == null
20 | ? ModalRoute.of(context)?.canPop == true
21 | : (showBackButton ?? false))
22 | ? IconButton(
23 | icon: ImageExt.fromPackage(CRLoggerAssets.assetsIcBack),
24 | color: color,
25 | tooltip: MaterialLocalizations.of(context).backButtonTooltip,
26 | onPressed: () => _onBackPressed(context),
27 | )
28 | : const SizedBox();
29 | }
30 |
31 | void _onBackPressed(BuildContext context) {
32 | if (onPressed != null) {
33 | onPressed?.call();
34 | } else {
35 | Navigator.maybePop(context);
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/lib/src/widget/cr_inspector.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/src/cr_logger_helper.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:inspector/inspector.dart';
4 |
5 | class CrInspector extends StatelessWidget {
6 | const CrInspector({
7 | required this.child,
8 | super.key,
9 | });
10 |
11 | final Widget child;
12 |
13 | @override
14 | Widget build(BuildContext context) {
15 | return ValueListenableBuilder(
16 | valueListenable: CRLoggerHelper.instance.inspectorNotifier,
17 | // ignore: Prefer-trailing-comma
18 | builder: (_, enabled, __) => Inspector(
19 | isEnabled: enabled,
20 | child: child,
21 | ),
22 | );
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/lib/src/widget/error_value_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/cr_logger.dart';
2 | import 'package:cr_logger/src/res/colors.dart';
3 | import 'package:cr_logger/src/res/styles.dart';
4 | import 'package:cr_logger/src/utils/parsers/url_parser.dart';
5 | import 'package:cr_logger/src/widget/copy_widget.dart';
6 | import 'package:cr_logger/src/widget/expand_arrow_button.dart';
7 | import 'package:cr_logger/src/widget/rounded_card.dart';
8 | import 'package:flutter/material.dart';
9 |
10 | class ErrorValueWidget extends StatefulWidget {
11 | const ErrorValueWidget({
12 | required this.errorBean,
13 | super.key,
14 | });
15 |
16 | final ErrorBean errorBean;
17 |
18 | @override
19 | _ErrorValueWidgetState createState() => _ErrorValueWidgetState();
20 | }
21 |
22 | class _ErrorValueWidgetState extends State {
23 | bool _expanded = false;
24 |
25 | @override
26 | Widget build(BuildContext context) {
27 | final statusCode = widget.errorBean.statusCode;
28 | final statusMessage = widget.errorBean.statusMessage;
29 | final url = widget.errorBean.url;
30 | final urlWithHiddenParams = getUrlWithHiddenParams(url.toString());
31 |
32 | return RoundedCard(
33 | child: Column(
34 | crossAxisAlignment: CrossAxisAlignment.start,
35 | children: [
36 | Row(
37 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
38 | children: [
39 | const Text('Error', style: CRStyle.subtitle1BlackSemiBold16),
40 | CopyWidget(onCopy: () => copyClipboard(context, url ?? '')),
41 | ],
42 | ),
43 | const SizedBox(height: 4),
44 |
45 | /// Status code and message
46 | if (statusCode != null && statusMessage != null)
47 | Row(
48 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
49 | children: [
50 | const Text(
51 | 'Status',
52 | style: CRStyle.bodyBlackMedium14,
53 | ),
54 | Container(
55 | decoration: BoxDecoration(
56 | color: CRLoggerColors.red,
57 | borderRadius: BorderRadius.circular(4),
58 | ),
59 | padding: const EdgeInsets.symmetric(
60 | horizontal: 10,
61 | vertical: 4,
62 | ),
63 | child: Text(
64 | '$statusCode $statusMessage',
65 | style: CRStyle.bodyWhiteSemiBold14,
66 | ),
67 | ),
68 | ],
69 | ),
70 | const Divider(height: 20),
71 |
72 | /// Link
73 | Row(
74 | crossAxisAlignment: CrossAxisAlignment.start,
75 | children: [
76 | Expanded(
77 | child: Padding(
78 | padding: const EdgeInsets.only(top: 6, bottom: 4),
79 | child: Text(
80 | urlWithHiddenParams,
81 | maxLines: _expanded ? null : 1,
82 | overflow: _expanded ? null : TextOverflow.ellipsis,
83 | style: CRStyle.bodyBlackRegular14,
84 | ),
85 | ),
86 | ),
87 | const SizedBox(width: 4),
88 | ExpandArrowButton(
89 | isExpanded: _expanded,
90 | onTap: () => setState(() => _expanded = !_expanded),
91 | ),
92 | ],
93 | ),
94 | ],
95 | ),
96 | );
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/lib/src/widget/expand_arrow_button.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math' as math;
2 |
3 | import 'package:cr_logger/generated/assets.dart';
4 | import 'package:cr_logger/src/extensions/extensions.dart';
5 | import 'package:flutter/material.dart';
6 |
7 | class ExpandArrowButton extends StatelessWidget {
8 | const ExpandArrowButton({
9 | required this.isExpanded,
10 | this.onTap,
11 | super.key,
12 | });
13 |
14 | final bool isExpanded;
15 | final VoidCallback? onTap;
16 |
17 | @override
18 | Widget build(BuildContext context) {
19 | return SizedBox.square(
20 | dimension: 28,
21 | child: Transform.rotate(
22 | angle: isExpanded ? math.pi : 0,
23 | child: IconButton(
24 | onPressed: onTap,
25 | icon: ImageExt.fromPackage(
26 | CRLoggerAssets.assetsArrowDown,
27 | height: 28,
28 | width: 28,
29 | ),
30 | iconSize: 28,
31 | splashRadius: 20,
32 | padding: EdgeInsets.zero,
33 | ),
34 | ),
35 | );
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/lib/src/widget/http_error_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/cr_logger.dart';
2 | import 'package:cr_logger/src/res/styles.dart';
3 | import 'package:cr_logger/src/widget/error_value_widget.dart';
4 | import 'package:cr_logger/src/widget/json_widget/json_widget.dart';
5 | import 'package:cr_logger/src/widget/rounded_card.dart';
6 | import 'package:flutter/material.dart';
7 |
8 | class HttpErrorWidget extends StatefulWidget {
9 | const HttpErrorWidget(this.httpBean, {super.key});
10 |
11 | final HttpBean httpBean;
12 |
13 | @override
14 | _HttpErrorWidgetState createState() => _HttpErrorWidgetState();
15 | }
16 |
17 | class _HttpErrorWidgetState extends State
18 | with AutomaticKeepAliveClientMixin {
19 | final _jsonWidgetErrorValueKey = const ValueKey('ErrorPageParams');
20 |
21 | @override
22 | bool get wantKeepAlive => true;
23 |
24 | @override
25 | Widget build(BuildContext context) {
26 | super.build(context);
27 |
28 | final errorBean = widget.httpBean.error;
29 |
30 | return errorBean == null
31 | ? const Center(
32 | child: Text(
33 | 'No error',
34 | style: CRStyle.bodyGreyMedium14,
35 | ),
36 | )
37 | : SingleChildScrollView(
38 | padding: const EdgeInsets.only(
39 | left: 16,
40 | right: 16,
41 | bottom: 16,
42 | ),
43 | child: Column(
44 | crossAxisAlignment: CrossAxisAlignment.start,
45 | children: [
46 | ErrorValueWidget(errorBean: errorBean),
47 | const SizedBox(height: 12),
48 |
49 | /// Error response
50 | RoundedCard(
51 | padding: const EdgeInsets.all(16),
52 | child: Column(
53 | crossAxisAlignment: CrossAxisAlignment.start,
54 | children: [
55 | const Text(
56 | 'Response:',
57 | style: CRStyle.subtitle1BlackSemiBold16,
58 | ),
59 | const SizedBox(height: 12),
60 | JsonWidget(
61 | _getJsonObj(errorBean),
62 | allExpandedNodes: true,
63 | key: _jsonWidgetErrorValueKey,
64 | ),
65 | ],
66 | ),
67 | ),
68 | ],
69 | ),
70 | );
71 | }
72 |
73 | Map? _getJsonObj(ErrorBean? error) {
74 | final errorData = error?.errorData;
75 |
76 | return errorData is Map
77 | ? errorData
78 | : {'Error': error?.errorData.toString() ?? ''};
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/lib/src/widget/json_widget/json_tree_colors.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | const nullColor = Colors.grey;
4 | const boolColor = Colors.orange;
5 |
6 | const jsonTreeColor = Color(0xFF2D45C3);
7 | const intColor = Color(0xFF199B4D);
8 | const doubleColor = Color(0xFF199B4D);
9 | const stringColor = Color(0xFFCD44D9);
10 |
--------------------------------------------------------------------------------
/lib/src/widget/json_widget/json_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_json_widget/cr_json_recycler.dart';
2 | import 'package:cr_logger/cr_logger.dart';
3 | import 'package:flutter/material.dart';
4 |
5 | class JsonWidget extends StatefulWidget {
6 | const JsonWidget(
7 | this.jsonObj, {
8 | this.notRoot,
9 | this.caption,
10 | this.allExpandedNodes = false,
11 | this.uncovered = 1,
12 | super.key,
13 | });
14 |
15 | final Map? jsonObj;
16 | final bool? notRoot;
17 | final Widget? caption;
18 | final bool allExpandedNodes;
19 | final int uncovered;
20 |
21 | @override
22 | JsonWidgetState createState() => JsonWidgetState();
23 | }
24 |
25 | class JsonWidgetState extends State {
26 | late final _jsonCtr = JsonRecyclerController(isExpanded: false);
27 |
28 | Map? _jsonWithHiddenParameters;
29 |
30 | @override
31 | void initState() {
32 | super.initState();
33 | _updateNodes();
34 | }
35 |
36 | @override
37 | Widget build(BuildContext context) {
38 | final jsonObj = widget.jsonObj;
39 |
40 | return jsonObj == null || jsonObj.isEmpty
41 | ? const SizedBox()
42 | : Padding(
43 | padding:
44 | EdgeInsets.only(left: (widget.notRoot ?? false) ? 14.0 : 0),
45 | child: Column(
46 | mainAxisSize: MainAxisSize.min,
47 | crossAxisAlignment: CrossAxisAlignment.start,
48 | children: [
49 | if (widget.caption != null)
50 | Padding(
51 | padding: const EdgeInsets.only(bottom: 3),
52 | child: widget.caption,
53 | ),
54 |
55 | /// JsonTreeView
56 | CustomScrollView(
57 | physics: const NeverScrollableScrollPhysics(),
58 | shrinkWrap: true,
59 | slivers: [
60 | CrJsonRecyclerSliver(
61 | jsonController: _jsonCtr,
62 | json: _jsonWithHiddenParameters,
63 | rootExpanded: true,
64 | ),
65 | ],
66 | ),
67 | ],
68 | ),
69 | );
70 | }
71 |
72 | @override
73 | void didUpdateWidget(covariant JsonWidget oldWidget) {
74 | super.didUpdateWidget(oldWidget);
75 | _updateNodes();
76 | if (oldWidget.allExpandedNodes != widget.allExpandedNodes) {
77 | _jsonCtr.changeState();
78 | }
79 | }
80 |
81 | /// Create Nodes3 = {map entry} "Test3" -> "Hidden"4 = {map entry} "Test4" -3 = {map entry} "Test3" -> "Hidden"> [_InternalLinkedHashMap]
82 | Map? _toTreeJson(Map jsonObj) {
83 | for (final obj in jsonObj.keys) {
84 | final isHidden = CRLoggerInitializer.instance.hiddenFields.contains(obj);
85 | if (isHidden) {
86 | jsonObj[obj] = 'Hidden';
87 | }
88 | }
89 |
90 | return jsonObj;
91 | }
92 |
93 | void _updateNodes() {
94 | if (widget.jsonObj != null) {
95 | _jsonWithHiddenParameters = _toTreeJson(widget.jsonObj!);
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/lib/src/widget/params_expansion_tile.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/cr_logger.dart';
2 | import 'package:cr_logger/src/res/colors.dart';
3 | import 'package:cr_logger/src/res/styles.dart';
4 | import 'package:cr_logger/src/widget/expand_arrow_button.dart';
5 | import 'package:cr_logger/src/widget/json_widget/json_widget.dart';
6 | import 'package:cr_logger/src/widget/rounded_card.dart';
7 | import 'package:flutter/material.dart';
8 |
9 | class ParamsExpansionTile extends StatefulWidget {
10 | const ParamsExpansionTile({
11 | required this.request,
12 | super.key,
13 | });
14 |
15 | final RequestBean? request;
16 |
17 | @override
18 | State createState() => _ParamsExpansionTileState();
19 | }
20 |
21 | class _ParamsExpansionTileState extends State {
22 | bool _isExpanded = false;
23 |
24 | @override
25 | Widget build(BuildContext context) {
26 | final paramsLength = widget.request?.params?.length ?? 0;
27 | final paramsIsNotEmpty = paramsLength != 0;
28 | const _jsonWidgetParamsValueKey = ValueKey('RequestPageParams');
29 |
30 | return RoundedCard(
31 | padding: const EdgeInsets.only(
32 | left: 16,
33 | top: 10,
34 | right: 16,
35 | bottom: 10,
36 | ),
37 | child: Column(
38 | children: [
39 | Row(
40 | children: [
41 | const Expanded(
42 | child: Text(
43 | 'Params',
44 | style: CRStyle.subtitle1BlackSemiBold16,
45 | ),
46 | ),
47 | Text(
48 | '$paramsLength',
49 | style: CRStyle.subtitle1BlackSemiBold16.copyWith(
50 | color: CRLoggerColors.grey,
51 | ),
52 | ),
53 | const SizedBox(width: 6),
54 | ExpandArrowButton(
55 | isExpanded: _isExpanded && paramsIsNotEmpty,
56 | onTap: paramsIsNotEmpty ? _expand : null,
57 | ),
58 | ],
59 | ),
60 | if (paramsIsNotEmpty)
61 | JsonWidget(
62 | widget.request?.params,
63 | key: _jsonWidgetParamsValueKey,
64 | allExpandedNodes: _isExpanded,
65 | ),
66 | ],
67 | ),
68 | );
69 | }
70 |
71 | void _expand() => setState(() => _isExpanded = !_isExpanded);
72 | }
73 |
--------------------------------------------------------------------------------
/lib/src/widget/proxy_input_dialog.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/src/cr_logger_helper.dart';
2 | import 'package:cr_logger/src/res/colors.dart';
3 | import 'package:cr_logger/src/res/styles.dart';
4 | import 'package:flutter/material.dart';
5 |
6 | class ProxyInputDialog extends StatefulWidget {
7 | const ProxyInputDialog({super.key});
8 |
9 | @override
10 | _ProxyInputDialogState createState() => _ProxyInputDialogState();
11 | }
12 |
13 | class _ProxyInputDialogState extends State {
14 | late TextEditingController iPCtrl;
15 | late TextEditingController portCtrl;
16 |
17 | @override
18 | void initState() {
19 | String? ip;
20 | String? port;
21 |
22 | final proxy = CRLoggerHelper.instance.getProxyFromSharedPref();
23 | if (proxy != null) {
24 | final items = proxy.split(':');
25 | ip = items.first;
26 | port = items[1];
27 | }
28 |
29 | iPCtrl = TextEditingController(text: ip ?? '');
30 | portCtrl = TextEditingController(text: port ?? '8888');
31 | super.initState();
32 | }
33 |
34 | @override
35 | void dispose() {
36 | iPCtrl.dispose();
37 | portCtrl.dispose();
38 | super.dispose();
39 | }
40 |
41 | @override
42 | Widget build(BuildContext context) {
43 | return AlertDialog(
44 | title: const Text('Proxy settings for Charles'),
45 | content: Column(
46 | crossAxisAlignment: CrossAxisAlignment.stretch,
47 | mainAxisSize: MainAxisSize.min,
48 | children: [
49 | const Text(
50 | 'Changes will be applied after restarting the app',
51 | style: CRStyle.captionGreyMedium12,
52 | ),
53 | TextField(
54 | // ignore: no-empty-block
55 | onChanged: (_) => setState(() {}),
56 | controller: iPCtrl,
57 | decoration: const InputDecoration(hintText: 'Enter new IP address'),
58 | ),
59 | TextField(
60 | // ignore: no-empty-block
61 | onChanged: (_) => setState(() {}),
62 | controller: portCtrl,
63 | decoration: const InputDecoration(hintText: 'Enter port'),
64 | ),
65 | ],
66 | ),
67 | actions: [
68 | TextButton(
69 | onPressed: _clearProxy,
70 | child: const DefaultTextStyle(
71 | style: TextStyle(color: CRLoggerColors.red),
72 | child: Text('CLEAR'),
73 | ),
74 | ),
75 | TextButton(
76 | onPressed: _closeDialog,
77 | child: const Text('CANCEL'),
78 | ),
79 | TextButton(
80 | onPressed:
81 | iPCtrl.text.isEmpty || portCtrl.text.isEmpty ? null : _saveProxy,
82 | child: const Text('SAVE'),
83 | ),
84 | ],
85 | );
86 | }
87 |
88 | void _closeDialog() => Navigator.of(context).pop();
89 |
90 | Future _saveProxy() async {
91 | final ip = iPCtrl.text.trim();
92 | final port = portCtrl.text.trim();
93 |
94 | if (ip.isNotEmpty && port.isNotEmpty) {
95 | final proxy = '$ip:$port';
96 | await CRLoggerHelper.instance.setProxyToSharedPref(proxy);
97 | }
98 | _closeDialog();
99 | }
100 |
101 | Future _clearProxy() async {
102 | await CRLoggerHelper.instance.setProxyToSharedPref(null);
103 | _closeDialog();
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/lib/src/widget/remove_log_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class RemoveLogWidget extends StatelessWidget {
4 | const RemoveLogWidget({
5 | this.onRemove,
6 | super.key,
7 | });
8 |
9 | final VoidCallback? onRemove;
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | return SizedBox.square(
14 | dimension: 28,
15 | child: IconButton(
16 | onPressed: onRemove,
17 | icon: const Icon(
18 | Icons.delete_outline,
19 | color: Colors.black45,
20 | ),
21 | iconSize: 24,
22 | splashRadius: 20,
23 | padding: EdgeInsets.zero,
24 | ),
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/lib/src/widget/rounded_card.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/src/res/colors.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | class RoundedCard extends StatelessWidget {
5 | const RoundedCard({
6 | required this.child,
7 | this.onTap,
8 | this.onLongTap,
9 | this.padding,
10 | super.key,
11 | });
12 |
13 | final Widget child;
14 | final VoidCallback? onTap;
15 | final VoidCallback? onLongTap;
16 | final EdgeInsetsGeometry? padding;
17 |
18 | @override
19 | Widget build(BuildContext context) {
20 | return Card(
21 | elevation: 0,
22 | margin: EdgeInsets.zero,
23 | shape: RoundedRectangleBorder(
24 | borderRadius: BorderRadius.circular(10),
25 | ),
26 | child: InkWell(
27 | onTap: onTap,
28 | onLongPress: onLongTap,
29 | borderRadius: BorderRadius.circular(10),
30 | child: Ink(
31 | decoration: BoxDecoration(
32 | color: CRLoggerColors.white,
33 | borderRadius: BorderRadius.circular(10),
34 | ),
35 | padding: padding ??
36 | const EdgeInsets.only(
37 | left: 16,
38 | top: 10,
39 | right: 16,
40 | bottom: 10,
41 | ),
42 | child: child,
43 | ),
44 | ),
45 | );
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/lib/src/widget/url_value_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/cr_logger.dart';
2 | import 'package:cr_logger/src/extensions/extensions.dart';
3 | import 'package:cr_logger/src/res/styles.dart';
4 | import 'package:cr_logger/src/utils/parsers/url_parser.dart';
5 | import 'package:cr_logger/src/widget/expand_arrow_button.dart';
6 | import 'package:cr_logger/src/widget/rounded_card.dart';
7 | import 'package:flutter/material.dart';
8 |
9 | class UrlValueWidget extends StatefulWidget {
10 | const UrlValueWidget({
11 | required this.url,
12 | this.requestTime,
13 | this.responseTime,
14 | super.key,
15 | });
16 |
17 | final String? url;
18 | final DateTime? requestTime;
19 | final DateTime? responseTime;
20 |
21 | @override
22 | _UrlValueWidgetState createState() => _UrlValueWidgetState();
23 | }
24 |
25 | class _UrlValueWidgetState extends State {
26 | bool _isExpanded = false;
27 |
28 | @override
29 | Widget build(BuildContext context) {
30 | final urlWithHiddenParams = getUrlWithHiddenParams(
31 | widget.url.toString(),
32 | showFullPath: _isExpanded,
33 | );
34 | final requestTime = widget.requestTime;
35 | final responseTime = widget.responseTime;
36 |
37 | return RoundedCard(
38 | onTap: () => setState(() => _isExpanded = !_isExpanded),
39 | onLongTap: () => copyClipboard(context, widget.url ?? ''),
40 | padding: const EdgeInsets.only(
41 | left: 16,
42 | top: 10,
43 | right: 16,
44 | bottom: 10,
45 | ),
46 | child: Row(
47 | crossAxisAlignment: CrossAxisAlignment.start,
48 | children: [
49 | Expanded(
50 | child: Column(
51 | crossAxisAlignment: CrossAxisAlignment.start,
52 | children: [
53 | const SizedBox(height: 8),
54 |
55 | /// URL
56 | Text(
57 | urlWithHiddenParams,
58 | maxLines: _isExpanded ? null : 1,
59 | overflow: _isExpanded ? null : TextOverflow.ellipsis,
60 | style: CRStyle.bodyBlackRegular14,
61 | ),
62 | const SizedBox(height: 4),
63 |
64 | /// Request time
65 | if (_isExpanded && requestTime != null)
66 | Padding(
67 | padding: const EdgeInsets.only(top: 6),
68 | child: Text(
69 | 'Request time: ${requestTime.formatTime(context)}',
70 | style: CRStyle.bodyGreyRegular14,
71 | ),
72 | ),
73 |
74 | /// Response time
75 | if (_isExpanded && responseTime != null)
76 | Padding(
77 | padding: const EdgeInsets.only(top: 6),
78 | child: Text(
79 | 'Response time: ${responseTime.formatTime(context)}',
80 | style: CRStyle.bodyGreyRegular14,
81 | ),
82 | ),
83 | ],
84 | ),
85 | ),
86 | const SizedBox(width: 4),
87 |
88 | /// Arrow button
89 | ExpandArrowButton(isExpanded: _isExpanded),
90 | ],
91 | ),
92 | );
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: cr_logger
2 | description: Powerful logging plugin. Supports android, ios and web platforms.
3 |
4 | version: 2.4.2
5 | homepage: https://github.com/Cleveroad/cr_logger
6 |
7 | topics:
8 | - tool
9 | - network
10 | - debug
11 | - logging
12 | - dio
13 |
14 | environment:
15 | sdk: ">=3.0.0 <4.0.0"
16 | flutter: ">=3.16.0"
17 |
18 | dependencies:
19 | flutter:
20 | sdk: flutter
21 | flutter_web_plugins:
22 | sdk: flutter
23 | http: ^1.1.2
24 |
25 | # MIT
26 | cr_json_widget: ^1.1.1
27 |
28 | # Network
29 | # MIT
30 | dio: ^5.4.0
31 | # MIT
32 | chopper: ^7.0.10
33 | # MIT
34 | logger: ^2.0.2+1
35 |
36 | # BSD
37 | package_info_plus: ^5.0.1
38 |
39 | # MIT
40 | uuid: ^3.0.7
41 |
42 | # MIT
43 | app_settings: ^5.1.1
44 |
45 | # BSD
46 | path_provider: ^2.1.2
47 | # BSD-3-Clause
48 | path: ^1.8.3
49 |
50 | # MIT
51 | inspector: ^2.1.0
52 |
53 | # BSD-3-Clause
54 | shared_preferences: ^2.2.2
55 | # MIT
56 | split_view: ^3.2.1
57 |
58 | # unknown
59 | # https://pub.dev/packages/synchronized/license
60 | synchronized: ^3.1.0
61 |
62 | # BSD-3-Clause
63 | js: ^0.6.7
64 |
65 | # BSD-3-Clause
66 | # https://stackoverflow.com/a/70757512
67 | platform: ^3.1.2
68 |
69 | # Apache-2.0
70 | infinite_scroll_pagination: ^4.0.0
71 | # MIT
72 | worker_manager: ^6.3.1
73 |
74 | # BSD-2-Clause
75 | sqflite: ^2.3.0
76 |
77 | dev_dependencies:
78 | flutter_test:
79 | sdk: flutter
80 | flutter_lints: ^3.0.1
81 |
82 | build_runner: ^2.4.7
83 |
84 | flutter:
85 | uses-material-design: true
86 | assets:
87 | - assets/
88 |
89 | fonts:
90 | - family: Epilogue
91 | fonts:
92 | - asset: fonts/Epilogue-Medium.ttf
93 | - asset: fonts/Epilogue-Regular.ttf
94 |
95 | plugin:
96 | platforms:
97 | android:
98 | package: com.cleveroad.cr_logger.cr_logger
99 | pluginClass: CrLoggerPlugin
100 | ios:
101 | pluginClass: CrLoggerPlugin
102 | web:
103 | pluginClass: CrLoggerWeb
104 | fileName: cr_logger_web.dart
105 |
106 |
--------------------------------------------------------------------------------
/screenshots/debug_log_screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/screenshots/debug_log_screenshot.png
--------------------------------------------------------------------------------
/screenshots/http-logs-example.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/screenshots/http-logs-example.gif
--------------------------------------------------------------------------------
/screenshots/http_db_log_screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/screenshots/http_db_log_screenshot.png
--------------------------------------------------------------------------------
/screenshots/http_error_screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/screenshots/http_error_screenshot.png
--------------------------------------------------------------------------------
/screenshots/http_log_screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/screenshots/http_log_screenshot.png
--------------------------------------------------------------------------------
/screenshots/http_request_screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/screenshots/http_request_screenshot.png
--------------------------------------------------------------------------------
/screenshots/http_response_screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/screenshots/http_response_screenshot.png
--------------------------------------------------------------------------------
/screenshots/http_search_screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/screenshots/http_search_screenshot.png
--------------------------------------------------------------------------------
/screenshots/logs_search_screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/screenshots/logs_search_screenshot.png
--------------------------------------------------------------------------------
/screenshots/plugin_banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/screenshots/plugin_banner.png
--------------------------------------------------------------------------------
/screenshots/quick_action_menu_screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/screenshots/quick_action_menu_screenshot.png
--------------------------------------------------------------------------------
/screenshots/screenshot-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/screenshots/screenshot-web.png
--------------------------------------------------------------------------------
/screenshots/settings-screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cleveroad/cr_logger/ad324c1aec547aca793690643999a6463fc69fc1/screenshots/settings-screenshot.png
--------------------------------------------------------------------------------
/test/replace_curly_braces_test.dart:
--------------------------------------------------------------------------------
1 | import 'package:cr_logger/src/constants.dart';
2 | import 'package:flutter_test/flutter_test.dart';
3 |
4 | void main() {
5 | group('patternOfParamsRegex tests', () {
6 | test('replace for string without parameters', () {
7 | const text = 'This is a test string.';
8 |
9 | expect(text.replaceAll(patternOfParamsRegex, ''), equals(text));
10 | });
11 |
12 | test('replace for string with one parameter', () {
13 | const text = 'Hello, {{name}}!';
14 |
15 | expect(
16 | text.replaceAll(patternOfParamsRegex, ''),
17 | equals('Hello, name!'),
18 | );
19 | });
20 |
21 | test('replace for string with several parameter', () {
22 | const text = 'The {{animal}} jumped over the {{object}}.';
23 |
24 | expect(
25 | text.replaceAll(patternOfParamsRegex, ''),
26 | equals('The animal jumped over the object.'),
27 | );
28 | });
29 |
30 | test(
31 | 'replace for string with one parameter, when parameter is a start of sentence',
32 | () {
33 | const text = '{{curly-braces}} are not allowed as parameter names.';
34 |
35 | expect(
36 | text.replaceAll(patternOfParamsRegex, ''),
37 | equals('curly-braces are not allowed as parameter names.'),
38 | );
39 | },
40 | );
41 |
42 | test('replace for string with nested parameters', () {
43 | const text = 'This {{has {{nested}}}} parameters.';
44 |
45 | expect(
46 | text.replaceAll(patternOfParamsRegex, ''),
47 | equals('This has nested parameters.'),
48 | );
49 | });
50 |
51 | test('replace for string, where parameters are adjacent to each other', () {
52 | const text = '{{param1}}{{param2}}';
53 |
54 | expect(text.replaceAll(patternOfParamsRegex, ''), equals('param1param2'));
55 | });
56 |
57 | test('replace for string when parameter in curly braces ', () {
58 | const text = 'This is a {{{parameter}}} in curly braces';
59 | expect(
60 | text.replaceAll(patternOfParamsRegex, ''),
61 | equals('This is a {parameter} in curly braces'),
62 | );
63 | });
64 | });
65 | }
66 |
--------------------------------------------------------------------------------