feat: add bloc observer (#7633)

* chore: bump version 0.8.8

* feat: add bloc observer

* chore: update comment

* chore: update comment
This commit is contained in:
Lucas 2025-03-27 14:17:47 +08:00 committed by GitHub
parent 4686e13390
commit 76cb23e233
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 170 additions and 221 deletions

View File

@ -3,7 +3,6 @@ import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/application/document_bloc.dart';
import 'package:appflowy/shared/icon_emoji_picker/flowy_icon_emoji_picker.dart';
import 'package:appflowy/shared/icon_emoji_picker/tab.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart'
show StringTranslateExtension;
@ -176,12 +175,7 @@ class _CalloutBlockComponentWidgetState
EmojiIconData result = EmojiIconData.emoji('📌');
try {
result = EmojiIconData(FlowyIconType.values.byName(type), icon);
} catch (e) {
Log.info(
'get emoji error with icon:[$icon], type:[$type] within calloutBlockComponentWidget',
e,
);
}
} catch (_) {}
return result;
}

View File

@ -238,8 +238,13 @@ extension TableNodeExtension on Node {
try {
final columnWidths =
parentTableNode.attributes[SimpleTableBlockKeys.columnWidths];
final width = columnWidths?[columnIndex.toString()];
return width ?? SimpleTableConstants.defaultColumnWidth;
final width = columnWidths?[columnIndex.toString()] as Object?;
if (width == null) {
return SimpleTableConstants.defaultColumnWidth;
}
return width.toDouble(
defaultValue: SimpleTableConstants.defaultColumnWidth,
);
} catch (e) {
Log.warn('get column width: $e');
return SimpleTableConstants.defaultColumnWidth;
@ -856,3 +861,18 @@ extension TableNodeExtension on Node {
return TableAlign.left;
}
}
extension on Object {
double toDouble({double defaultValue = 0}) {
if (this is double) {
return this as double;
}
if (this is String) {
return double.tryParse(this as String) ?? defaultValue;
}
if (this is int) {
return (this as int).toDouble();
}
return defaultValue;
}
}

View File

@ -119,7 +119,7 @@ class FlowyRunner {
// this task should be second task, for handling memory leak.
// there's a flag named _enable in memory_leak_detector.dart. If it's false, the task will be ignored.
MemoryLeakDetectorTask(),
const DebugTask(),
DebugTask(),
const FeatureFlagTask(),
// localization

View File

@ -17,7 +17,6 @@ import 'package:appflowy/workspace/application/sidebar/rename_view/rename_view_b
import 'package:appflowy/workspace/application/tabs/tabs_bloc.dart';
import 'package:appflowy/workspace/application/view/view_ext.dart';
import 'package:appflowy/workspace/presentation/command_palette/command_palette.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
import 'package:easy_localization/easy_localization.dart';
@ -64,7 +63,6 @@ class InitAppWidgetTask extends LaunchTask {
child: widget,
);
Bloc.observer = ApplicationBlocObserver();
runApp(
EasyLocalization(
supportedLocales: const [
@ -283,14 +281,6 @@ class AppGlobals {
static BuildContext get context => rootNavKey.currentContext!;
}
class ApplicationBlocObserver extends BlocObserver {
@override
void onError(BlocBase bloc, Object error, StackTrace stackTrace) {
Log.debug(error);
super.onError(bloc, error, stackTrace);
}
}
Future<AppTheme> appTheme(String themeName) async {
if (themeName.isEmpty) {
return AppTheme.fallback;

View File

@ -1,18 +1,45 @@
import 'package:appflowy/startup/startup.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:talker/talker.dart';
import 'package:talker_bloc_logger/talker_bloc_logger.dart';
import 'package:universal_platform/universal_platform.dart';
import '../startup.dart';
class DebugTask extends LaunchTask {
const DebugTask();
DebugTask();
final Talker talker = Talker();
@override
Future<void> initialize(LaunchContext context) async {
// the hotkey manager is not supported on mobile
// hide the keyboard on mobile
if (UniversalPlatform.isMobile && kDebugMode) {
await SystemChannels.textInput.invokeMethod('TextInput.hide');
}
// log the bloc events
if (kDebugMode) {
Bloc.observer = TalkerBlocObserver(
talker: talker,
settings: TalkerBlocLoggerSettings(
// Disabled by default to prevent mixing with AppFlowy logs
// Enable to observe all bloc events
enabled: false,
printEventFullData: false,
printStateFullData: false,
printChanges: true,
printClosings: true,
printCreations: true,
transitionFilter: (_, transition) {
// By default, observe all transitions
// You can add your own filter here if needed
// when you want to observer a specific bloc
return true;
},
),
);
}
}
@override

View File

@ -331,16 +331,6 @@ class SpaceBloc extends Bloc<SpaceEvent, SpaceState> {
final (spaces, _, _) = await _getSpaces();
final currentSpace = await _getLastOpenedSpace(spaces);
Log.info(
'receive space update, current space: ${currentSpace?.name}(${currentSpace?.id})',
);
for (var i = 0; i < spaces.length; i++) {
Log.info(
'receive space update[$i]: ${spaces[i].name}(${spaces[i].id})',
);
}
emit(
state.copyWith(
spaces: spaces,
@ -496,7 +486,6 @@ class SpaceBloc extends Bloc<SpaceEvent, SpaceState> {
}
void _initial(UserProfilePB userProfile, String workspaceId) {
Log.info('initial(or reset) space bloc: $workspaceId, ${userProfile.id}');
_workspaceService = WorkspaceService(workspaceId: workspaceId);
this.userProfile = userProfile;
@ -507,7 +496,6 @@ class SpaceBloc extends Bloc<SpaceEvent, SpaceState> {
workspaceId: workspaceId,
)..start(
sectionChanged: (result) async {
Log.info('did receive section views changed');
if (isClosed) {
return;
}

View File

@ -144,34 +144,34 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral/.symlinks/plugins/window_manager/macos
SPEC CHECKSUMS:
app_links: 10e0a0ab602ffaf34d142cd4862f29d34b303b2a
appflowy_backend: 865496343de667fc8c600e04b9fd05234e130cf9
auto_updater_macos: 3e3462c418fe4e731917eacd8d28eef7af84086d
bitsdojo_window_macos: 44e3b8fe3dd463820e0321f6256c5b1c16bb6a00
connectivity_plus: 18d3c32514c886e046de60e9c13895109866c747
desktop_drop: 69eeff437544aa619c8db7f4481b3a65f7696898
device_info_plus: ce1b7762849d3ec103d0e0517299f2db7ad60720
file_selector_macos: cc3858c981fe6889f364731200d6232dac1d812d
flowy_infra_ui: 03301a39ad118771adbf051a664265c61c507f38
app_links: 9028728e32c83a0831d9db8cf91c526d16cc5468
appflowy_backend: 464aeb3e5c6966a41641a2111e5ead72ce2695f7
auto_updater_macos: 3a42f1a06be6981f1a18be37e6e7bf86aa732118
bitsdojo_window_macos: 7959fb0ca65a3ccda30095c181ecb856fae48ea9
connectivity_plus: e74b9f74717d2d99d45751750e266e55912baeb5
desktop_drop: e0b672a7d84c0a6cbc378595e82cdb15f2970a43
device_info_plus: a56e6e74dbbd2bb92f2da12c64ddd4f67a749041
file_selector_macos: 6280b52b459ae6c590af5d78fc35c7267a3c4b31
flowy_infra_ui: 8760ff42a789de40bf5007a5f176b454722a341e
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
HotKey: 400beb7caa29054ea8d864c96f5ba7e5b4852277
hotkey_manager: c32bf0bfe8f934b7bc17ab4ad5c4c142960b023c
irondash_engine_context: da62996ee25616d2f01bbeb85dc115d813359478
local_notifier: e9506bc66fc70311e8bc7291fb70f743c081e4ff
package_info_plus: 12f1c5c2cfe8727ca46cbd0b26677728972d9a5b
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
hotkey_manager: b443f35f4d772162937aa73fd8995e579f8ac4e2
irondash_engine_context: 893c7d96d20ce361d7e996f39d360c4c2f9869ba
local_notifier: ebf072651e35ae5e47280ad52e2707375cb2ae4e
package_info_plus: f0052d280d17aa382b932f399edf32507174e870
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
ReachabilitySwift: 32793e867593cfc1177f5d16491e3a197d2fccda
screen_retriever_macos: 776e0fa5d42c6163d2bf772d22478df4b302b161
screen_retriever_macos: 452e51764a9e1cdb74b3c541238795849f21557f
Sentry: 1fe34e9c2cbba1e347623610d26db121dcb569f1
sentry_flutter: a39c2a2d67d5e5b9cb0b94a4985c76dd5b3fc737
share_plus: 1fa619de8392a4398bfaf176d441853922614e89
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
sentry_flutter: e24b397f9a61fa5bbefd8279c3b2242ca86faa90
share_plus: 510bf0af1a42cd602274b4629920c9649c52f4cc
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
Sparkle: 5f8960a7a119aa7d45dacc0d5837017170bc5675
sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d
super_native_extensions: 85efee3a7495b46b04befcfc86ed12069264ebf3
url_launcher_macos: c82c93949963e55b228a30115bd219499a6fe404
webview_flutter_wkwebview: 0982481e3d9c78fd5c6f62a002fcd24fc791f1e4
window_manager: 3a1844359a6295ab1e47659b1a777e36773cd6e8
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
super_native_extensions: c2795d6d9aedf4a79fae25cb6160b71b50549189
url_launcher_macos: 0fba8ddabfc33ce0a9afe7c5fef5aab3d8d2d673
webview_flutter_wkwebview: 44d4dee7d7056d5ad185d25b38404436d56c547c
window_manager: 1d01fa7ac65a6e6f83b965471b1a7fdd3f06166c
PODFILE CHECKSUM: 0532f3f001ca3110b8be345d6491fff690e95823

View File

@ -1,9 +1,13 @@
import Cocoa
import FlutterMacOS
@NSApplicationMain
@main
class AppDelegate: FlutterAppDelegate {
override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
return true
}
override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool {
return true
}
}

View File

@ -4,11 +4,11 @@ import 'dart:ffi';
import 'dart:io';
import 'dart:isolate';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/rust_stream.dart';
import 'package:ffi/ffi.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:logger/logger.dart';
import 'ffi.dart' as ffi;
@ -62,28 +62,15 @@ class RustLogStreamReceiver {
late StreamController<Uint8List> _streamController;
late StreamSubscription<Uint8List> _subscription;
int get port => _ffiPort.sendPort.nativePort;
late Logger _logger;
RustLogStreamReceiver._internal() {
_ffiPort = RawReceivePort();
_streamController = StreamController();
_ffiPort.handler = _streamController.add;
_logger = Logger(
printer: PrettyPrinter(
methodCount: 0, // number of method calls to be displayed
errorMethodCount: 8, // number of method calls if stacktrace is provided
lineLength: 120, // width of the output
colors: false, // Colorful log messages
printEmojis: false, // Print an emoji for each log message
dateTimeFormat:
DateTimeFormat.none, // Should each log print contain a timestamp
),
level: kDebugMode ? Level.trace : Level.info,
);
_subscription = _streamController.stream.listen((data) {
String decodedString = utf8.decode(data);
_logger.i(decodedString);
Log.info(decodedString);
});
}

View File

@ -3,64 +3,43 @@ import 'dart:ffi';
import 'package:ffi/ffi.dart' as ffi;
import 'package:flutter/foundation.dart';
import 'package:logger/logger.dart';
import 'package:talker/talker.dart';
import 'ffi.dart';
class Log {
static final shared = Log();
// ignore: unused_field
late Logger _logger;
bool _enabled = false;
late Talker _logger;
bool enableFlutterLog = true;
// used to disable log in tests
@visibleForTesting
bool disableLog = false;
Log() {
_logger = Logger(
printer: PrettyPrinter(
methodCount: 2, // Number of method calls to be displayed
errorMethodCount: 8, // Number of method calls if stacktrace is provided
lineLength: 120, // Width of the output
colors: true, // Colorful log messages
printEmojis: true, // Print an emoji for each log message
),
level: kDebugMode ? Level.trace : Level.info,
_logger = Talker(
filter: LogLevelTalkerFilter(),
);
}
static void enableFlutterLog() {
shared._enabled = true;
}
// Generic internal logging function to reduce code duplication
static void _log(Level level, int rustLevel, dynamic msg,
[dynamic error, StackTrace? stackTrace]) {
if (shared._enabled) {
switch (level) {
case Level.info:
shared._logger.i(msg, stackTrace: stackTrace);
break;
case Level.debug:
shared._logger.d(msg, stackTrace: stackTrace);
break;
case Level.warning:
shared._logger.w(msg, stackTrace: stackTrace);
break;
case Level.error:
shared._logger.e(msg, stackTrace: stackTrace);
break;
case Level.trace:
shared._logger.t(msg, stackTrace: stackTrace);
break;
default:
shared._logger.log(level, msg, stackTrace: stackTrace);
}
static void _log(
LogLevel level,
int rustLevel,
dynamic msg, [
dynamic error,
StackTrace? stackTrace,
]) {
// only forward logs to flutter in debug mode, otherwise log to rust to
// persist logs in the file system
if (shared.enableFlutterLog && kDebugMode) {
shared._logger.log(msg, logLevel: level, stackTrace: stackTrace);
} else {
String formattedMessage = _formatMessageWithStackTrace(msg, stackTrace);
rust_log(rustLevel, toNativeUtf8(formattedMessage));
}
String formattedMessage = _formatMessageWithStackTrace(msg, stackTrace);
rust_log(rustLevel, toNativeUtf8(formattedMessage));
}
static void info(dynamic msg, [dynamic error, StackTrace? stackTrace]) {
@ -68,7 +47,7 @@ class Log {
return;
}
_log(Level.info, 0, msg, error, stackTrace);
_log(LogLevel.info, 0, msg, error, stackTrace);
}
static void debug(dynamic msg, [dynamic error, StackTrace? stackTrace]) {
@ -76,7 +55,7 @@ class Log {
return;
}
_log(Level.debug, 1, msg, error, stackTrace);
_log(LogLevel.debug, 1, msg, error, stackTrace);
}
static void warn(dynamic msg, [dynamic error, StackTrace? stackTrace]) {
@ -84,7 +63,7 @@ class Log {
return;
}
_log(Level.warning, 3, msg, error, stackTrace);
_log(LogLevel.warning, 3, msg, error, stackTrace);
}
static void trace(dynamic msg, [dynamic error, StackTrace? stackTrace]) {
@ -92,7 +71,7 @@ class Log {
return;
}
_log(Level.trace, 2, msg, error, stackTrace);
_log(LogLevel.verbose, 2, msg, error, stackTrace);
}
static void error(dynamic msg, [dynamic error, StackTrace? stackTrace]) {
@ -100,7 +79,7 @@ class Log {
return;
}
_log(Level.error, 4, msg, error, stackTrace);
_log(LogLevel.error, 4, msg, error, stackTrace);
}
}
@ -119,3 +98,11 @@ String _formatMessageWithStackTrace(dynamic msg, StackTrace? stackTrace) {
}
return msg.toString();
}
class LogLevelTalkerFilter implements TalkerFilter {
@override
bool filter(TalkerData data) {
// filter out the debug logs in release mode
return kDebugMode ? true : data.logLevel != LogLevel.debug;
}
}

View File

@ -14,7 +14,7 @@ dependencies:
ffi: ^2.0.2
isolates: ^3.0.3+8
protobuf: ^3.1.0
logger: ^2.4.0
talker: ^4.7.1
plugin_platform_interface: ^2.1.3
appflowy_result:
path: ../appflowy_result

View File

@ -1,7 +1,7 @@
name: appflowy_result
description: "A new Flutter package project."
version: 0.0.1
homepage:
homepage: https://github.com/appflowy-io/appflowy
environment:
sdk: ">=3.3.0 <4.0.0"
@ -9,40 +9,3 @@ environment:
dev_dependencies:
flutter_lints: ^3.0.0
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter packages.
flutter:
# To add assets to your package, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
#
# For details regarding assets in packages, see
# https://flutter.dev/assets-and-images/#from-packages
#
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware
# To add custom fonts to your package, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts in packages, see
# https://flutter.dev/custom-fonts/#from-packages

View File

@ -1,5 +1,5 @@
name: flowy_infra
description: A new Flutter package project.
description: AppFlowy Infra.
version: 0.0.1
homepage: https://appflowy.io
@ -15,7 +15,7 @@ dependencies:
path: ^1.8.2
time: ">=2.0.0"
uuid: ">=2.2.2"
bloc: ^8.1.2
bloc: ^9.0.0
freezed_annotation: ^2.1.0
file_picker: ^8.0.2
file: ^7.0.0
@ -25,40 +25,3 @@ dev_dependencies:
flutter_lints: ^3.0.1
freezed: ^2.4.7
json_serializable: ^6.5.4
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter.
flutter:
# To add assets to your package, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
#
# For details regarding assets in packages, see
# https://flutter.dev/assets-and-images/#from-packages
#
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware.
# To add custom fonts to your package, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts in packages, see
# https://flutter.dev/custom-fonts/#from-packages

View File

@ -1,7 +1,7 @@
name: flowy_infra_ui_platform_interface
description: A new Flutter package project.
version: 0.0.1
homepage:
homepage: https://github.com/appflowy-io/appflowy
environment:
sdk: ">=2.12.0 <3.0.0"
@ -17,5 +17,3 @@ dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^3.0.1
flutter:

View File

@ -1,7 +1,7 @@
name: flowy_infra_ui_web
description: A new Flutter package project.
version: 0.0.1
homepage:
homepage: https://github.com/appflowy-io/appflowy
publish_to: none
environment:
@ -25,4 +25,4 @@ flutter:
platforms:
web:
pluginClass: FlowyInfraUIPlugin
fileName: flowy_infra_ui_web.dart
fileName: flowy_infra_ui_web.dart

View File

@ -30,6 +30,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.11"
ansicolor:
dependency: transitive
description:
name: ansicolor
sha256: "50e982d500bc863e1d703448afdbf9e5a72eb48840a4f766fa361ffd6877055f"
url: "https://pub.dev"
source: hosted
version: "2.0.3"
any_date:
dependency: "direct main"
description:
@ -253,18 +261,18 @@ packages:
dependency: "direct main"
description:
name: bloc
sha256: "106842ad6569f0b60297619e9e0b1885c2fb9bf84812935490e6c5275777804e"
sha256: "52c10575f4445c61dd9e0cafcc6356fdd827c4c64dd7945ef3c4105f6b6ac189"
url: "https://pub.dev"
source: hosted
version: "8.1.4"
version: "9.0.0"
bloc_test:
dependency: "direct dev"
description:
name: bloc_test
sha256: "165a6ec950d9252ebe36dc5335f2e6eb13055f33d56db0eeb7642768849b43d2"
sha256: "1dd549e58be35148bc22a9135962106aa29334bc1e3f285994946a1057b29d7b"
url: "https://pub.dev"
source: hosted
version: "9.1.7"
version: "10.0.0"
boolean_selector:
dependency: transitive
description:
@ -783,10 +791,10 @@ packages:
dependency: "direct main"
description:
name: flutter_bloc
sha256: b594505eac31a0518bdcb4b5b79573b8d9117b193cc80cc12e17d639b10aa27a
sha256: "1046d719fbdf230330d3443187cc33cc11963d15c9089f6cc56faa42a4c5f0cc"
url: "https://pub.dev"
source: hosted
version: "8.1.6"
version: "9.1.0"
flutter_cache_manager:
dependency: "direct main"
description:
@ -1331,14 +1339,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.1.6"
logger:
dependency: transitive
description:
name: logger
sha256: be4b23575aac7ebf01f225a241eb7f6b5641eeaf43c6a8613510fc2f8cf187d1
url: "https://pub.dev"
source: hosted
version: "2.5.0"
logging:
dependency: transitive
description:
@ -2186,6 +2186,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.1.3"
talker:
dependency: "direct main"
description:
name: talker
sha256: "45abef5b92f9b9bd42c3f20133ad4b20ab12e1da2aa206fc0a40ea874bed7c5d"
url: "https://pub.dev"
source: hosted
version: "4.7.1"
talker_bloc_logger:
dependency: "direct main"
description:
name: talker_bloc_logger
sha256: "2214a5f6ef9ff33494dc6149321c270356962725cc8fc1a485d44b1d9b812ddd"
url: "https://pub.dev"
source: hosted
version: "4.7.1"
talker_logger:
dependency: transitive
description:
name: talker_logger
sha256: ed9b20b8c09efff9f6b7c63fc6630ee2f84aa92661ae09e5ba04e77272bf2ad2
url: "https://pub.dev"
source: hosted
version: "4.7.1"
term_glyph:
dependency: transitive
description:

View File

@ -33,7 +33,7 @@ dependencies:
# BitsDojo Window for Windows
bitsdojo_window: ^0.1.6
bloc: ^8.1.2
bloc: ^9.0.0
cached_network_image: ^3.3.0
calendar_view:
git:
@ -67,7 +67,7 @@ dependencies:
flutter:
sdk: flutter
flutter_animate: ^4.5.0
flutter_bloc: ^8.1.3
flutter_bloc: ^9.1.0
flutter_cache_manager: ^3.3.1
flutter_chat_core: 0.0.2
flutter_chat_ui: ^2.0.0-dev.1
@ -148,9 +148,13 @@ dependencies:
xml: ^6.5.0
window_manager: ^0.4.3
saver_gallery: ^4.0.1
talker_bloc_logger: ^4.7.1
talker: ^4.7.1
dev_dependencies:
bloc_test: ^9.1.2
# Introduce talker to log the bloc events, and only log the events in the development mode
bloc_test: ^10.0.0
build_runner: ^2.4.9
envied_generator: ^1.0.1
flutter_lints: ^5.0.0