Merge pull request #1506 from GetStream/fix/pana

This commit is contained in:
Sahil Kumar
2023-04-20 19:39:23 +05:30
committed by GitHub
40 changed files with 2156 additions and 1840 deletions
+1 -1
View File
@@ -27,7 +27,7 @@ dependencies:
dev_dependencies: dev_dependencies:
build_runner: ^2.3.3 build_runner: ^2.3.3
dart_code_metrics: ^5.7.0 dart_code_metrics: ^5.7.2
freezed: ^2.3.2 freezed: ^2.3.2
json_serializable: ^6.6.1 json_serializable: ^6.6.1
mocktail: ^0.3.0 mocktail: ^0.3.0
@@ -7,8 +7,7 @@ import 'package:flutter/widgets.dart';
/// A registry to track some [Element]s in the tree. /// A registry to track some [Element]s in the tree.
class RegistryWidget extends StatefulWidget { class RegistryWidget extends StatefulWidget {
/// Creates a [RegistryWidget]. /// Creates a [RegistryWidget].
const RegistryWidget({Key? key, this.elementNotifier, required this.child}) const RegistryWidget({super.key, this.elementNotifier, required this.child});
: super(key: key);
/// The widget below this widget in the tree. /// The widget below this widget in the tree.
final Widget child; final Widget child;
@@ -28,8 +27,7 @@ class RegistryWidget extends StatefulWidget {
/// [RegistryWidget]. /// [RegistryWidget].
class RegisteredElementWidget extends ProxyWidget { class RegisteredElementWidget extends ProxyWidget {
/// Creates a [RegisteredElementWidget]. /// Creates a [RegisteredElementWidget].
const RegisteredElementWidget({Key? key, required Widget child}) const RegisteredElementWidget({super.key, required super.child});
: super(key: key, child: child);
@override @override
Element createElement() => _RegisteredElement(this); Element createElement() => _RegisteredElement(this);
@@ -47,10 +45,9 @@ class _RegistryWidgetState extends State<RegistryWidget> {
class _InheritedRegistryWidget extends InheritedWidget { class _InheritedRegistryWidget extends InheritedWidget {
const _InheritedRegistryWidget({ const _InheritedRegistryWidget({
Key? key,
required this.state, required this.state,
required Widget child, required super.child,
}) : super(key: key, child: child); });
final _RegistryWidgetState state; final _RegistryWidgetState state;
@@ -59,7 +56,7 @@ class _InheritedRegistryWidget extends InheritedWidget {
} }
class _RegisteredElement extends ProxyElement { class _RegisteredElement extends ProxyElement {
_RegisteredElement(ProxyWidget widget) : super(widget); _RegisteredElement(super.widget);
@override @override
void notifyClients(ProxyWidget oldWidget) {} void notifyClients(ProxyWidget oldWidget) {}
@@ -25,7 +25,7 @@ import 'package:stream_chat_flutter/scrollable_positioned_list/src/scroll_view.d
class PositionedList extends StatefulWidget { class PositionedList extends StatefulWidget {
/// Create a [PositionedList]. /// Create a [PositionedList].
const PositionedList({ const PositionedList({
Key? key, super.key,
required this.itemCount, required this.itemCount,
required this.itemBuilder, required this.itemBuilder,
this.separatorBuilder, this.separatorBuilder,
@@ -44,9 +44,8 @@ class PositionedList extends StatefulWidget {
this.addRepaintBoundaries = true, this.addRepaintBoundaries = true,
this.addAutomaticKeepAlives = true, this.addAutomaticKeepAlives = true,
this.keyboardDismissBehavior, this.keyboardDismissBehavior,
}) : assert((positionedIndex == 0) || (positionedIndex < itemCount), }) : assert((positionedIndex == 0) || (positionedIndex < itemCount),
'positionedIndex cannot be 0 and must be smaller than itemCount'), 'positionedIndex cannot be 0 and must be smaller than itemCount');
super(key: key);
/// Called to find the new index of a child based on its key in case of /// Called to find the new index of a child based on its key in case of
/// reordering. /// reordering.
@@ -272,7 +271,7 @@ class _PositionedListState extends State<PositionedList> {
: widget.reverse : widget.reverse
? widget.padding?.copyWith(left: 0) ? widget.padding?.copyWith(left: 0)
: widget.padding?.copyWith(right: 0)) ?? : widget.padding?.copyWith(right: 0)) ??
const EdgeInsets.all(0); EdgeInsets.zero;
EdgeInsets get _centerSliverPadding => widget.scrollDirection == Axis.vertical EdgeInsets get _centerSliverPadding => widget.scrollDirection == Axis.vertical
? widget.reverse ? widget.reverse
@@ -283,14 +282,14 @@ class _PositionedListState extends State<PositionedList> {
bottom: bottom:
widget.positionedIndex == 0 ? widget.padding!.bottom : 0, widget.positionedIndex == 0 ? widget.padding!.bottom : 0,
) ?? ) ??
const EdgeInsets.all(0) EdgeInsets.zero
: widget.padding?.copyWith( : widget.padding?.copyWith(
top: widget.positionedIndex == 0 ? widget.padding!.top : 0, top: widget.positionedIndex == 0 ? widget.padding!.top : 0,
bottom: widget.positionedIndex == widget.itemCount - 1 bottom: widget.positionedIndex == widget.itemCount - 1
? widget.padding!.bottom ? widget.padding!.bottom
: 0, : 0,
) ?? ) ??
const EdgeInsets.all(0) EdgeInsets.zero
: widget.reverse : widget.reverse
? widget.padding?.copyWith( ? widget.padding?.copyWith(
left: widget.positionedIndex == widget.itemCount - 1 left: widget.positionedIndex == widget.itemCount - 1
@@ -298,23 +297,23 @@ class _PositionedListState extends State<PositionedList> {
: 0, : 0,
right: widget.positionedIndex == 0 ? widget.padding!.right : 0, right: widget.positionedIndex == 0 ? widget.padding!.right : 0,
) ?? ) ??
const EdgeInsets.all(0) EdgeInsets.zero
: widget.padding?.copyWith( : widget.padding?.copyWith(
left: widget.positionedIndex == 0 ? widget.padding!.left : 0, left: widget.positionedIndex == 0 ? widget.padding!.left : 0,
right: widget.positionedIndex == widget.itemCount - 1 right: widget.positionedIndex == widget.itemCount - 1
? widget.padding!.right ? widget.padding!.right
: 0, : 0,
) ?? ) ??
const EdgeInsets.all(0); EdgeInsets.zero;
EdgeInsets get _trailingSliverPadding => EdgeInsets get _trailingSliverPadding =>
widget.scrollDirection == Axis.vertical widget.scrollDirection == Axis.vertical
? widget.reverse ? widget.reverse
? widget.padding?.copyWith(bottom: 0) ?? const EdgeInsets.all(0) ? widget.padding?.copyWith(bottom: 0) ?? EdgeInsets.zero
: widget.padding?.copyWith(top: 0) ?? const EdgeInsets.all(0) : widget.padding?.copyWith(top: 0) ?? EdgeInsets.zero
: widget.reverse : widget.reverse
? widget.padding?.copyWith(right: 0) ?? const EdgeInsets.all(0) ? widget.padding?.copyWith(right: 0) ?? EdgeInsets.zero
: widget.padding?.copyWith(left: 0) ?? const EdgeInsets.all(0); : widget.padding?.copyWith(left: 0) ?? EdgeInsets.zero;
void _schedulePositionNotificationUpdate() { void _schedulePositionNotificationUpdate() {
if (!updateScheduled) { if (!updateScheduled) {
@@ -7,8 +7,7 @@ import 'package:flutter/widgets.dart';
/// Widget whose [Element] calls a callback when the element is mounted. /// Widget whose [Element] calls a callback when the element is mounted.
class PostMountCallback extends StatelessWidget { class PostMountCallback extends StatelessWidget {
/// Creates a [PostMountCallback] widget. /// Creates a [PostMountCallback] widget.
const PostMountCallback({required this.child, this.callback, Key? key}) const PostMountCallback({required this.child, this.callback, super.key});
: super(key: key);
/// The widget below this widget in the tree. /// The widget below this widget in the tree.
final Widget child; final Widget child;
@@ -24,7 +23,7 @@ class PostMountCallback extends StatelessWidget {
} }
class _PostMountCallbackElement extends StatelessElement { class _PostMountCallbackElement extends StatelessElement {
_PostMountCallbackElement(PostMountCallback widget) : super(widget); _PostMountCallbackElement(PostMountCallback super.widget);
@override @override
void mount(Element? parent, dynamic newSlot) { void mount(Element? parent, dynamic newSlot) {
@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'package:flutter/gestures.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:stream_chat_flutter/scrollable_positioned_list/src/viewport.dart'; import 'package:stream_chat_flutter/scrollable_positioned_list/src/viewport.dart';
@@ -14,36 +13,24 @@ import 'package:stream_chat_flutter/scrollable_positioned_list/src/viewport.dart
class UnboundedCustomScrollView extends CustomScrollView { class UnboundedCustomScrollView extends CustomScrollView {
/// {@macro custom_scroll_view} /// {@macro custom_scroll_view}
const UnboundedCustomScrollView({ const UnboundedCustomScrollView({
Key? key, super.key,
Axis scrollDirection = Axis.vertical, super.scrollDirection,
bool reverse = false, super.reverse,
ScrollController? controller, super.controller,
bool? primary, super.primary,
ScrollPhysics? physics, super.physics,
bool shrinkWrap = false, super.shrinkWrap,
Key? center, super.center,
double anchor = 0.0, double anchor = 0.0,
double? cacheExtent, super.cacheExtent,
List<Widget> slivers = const <Widget>[], super.slivers,
int? semanticChildCount, super.semanticChildCount,
DragStartBehavior dragStartBehavior = DragStartBehavior.start, super.dragStartBehavior,
ScrollViewKeyboardDismissBehavior? keyboardDismissBehavior, ScrollViewKeyboardDismissBehavior? keyboardDismissBehavior,
}) : _anchor = anchor, }) : _anchor = anchor,
super( super(
key: key,
keyboardDismissBehavior: keyboardDismissBehavior ?? keyboardDismissBehavior: keyboardDismissBehavior ??
ScrollViewKeyboardDismissBehavior.manual, ScrollViewKeyboardDismissBehavior.manual,
scrollDirection: scrollDirection,
reverse: reverse,
controller: controller,
primary: primary,
physics: physics,
shrinkWrap: shrinkWrap,
center: center,
cacheExtent: cacheExtent,
semanticChildCount: semanticChildCount,
dragStartBehavior: dragStartBehavior,
slivers: slivers,
); );
// [CustomScrollView] enforces constraints on [CustomScrollView.anchor], so // [CustomScrollView] enforces constraints on [CustomScrollView.anchor], so
@@ -35,7 +35,7 @@ class ScrollablePositionedList extends StatefulWidget {
const ScrollablePositionedList.builder({ const ScrollablePositionedList.builder({
required this.itemCount, required this.itemCount,
required this.itemBuilder, required this.itemBuilder,
Key? key, super.key,
this.itemScrollController, this.itemScrollController,
ItemPositionsListener? itemPositionsListener, ItemPositionsListener? itemPositionsListener,
this.initialScrollIndex = 0, this.initialScrollIndex = 0,
@@ -52,16 +52,15 @@ class ScrollablePositionedList extends StatefulWidget {
this.findChildIndexCallback, this.findChildIndexCallback,
this.keyboardDismissBehavior, this.keyboardDismissBehavior,
}) : itemPositionsNotifier = itemPositionsListener as ItemPositionsNotifier?, }) : itemPositionsNotifier = itemPositionsListener as ItemPositionsNotifier?,
separatorBuilder = null, separatorBuilder = null;
super(key: key);
/// Create a [ScrollablePositionedList] whose items are provided by /// Create a [ScrollablePositionedList] whose items are provided by
/// [itemBuilder] and separators provided by [separatorBuilder]. /// [itemBuilder] and separators provided by [separatorBuilder].
const ScrollablePositionedList.separated({ const ScrollablePositionedList.separated({
required this.itemCount, required this.itemCount,
required this.itemBuilder, required this.itemBuilder,
required this.separatorBuilder, required IndexedWidgetBuilder this.separatorBuilder,
Key? key, super.key,
this.itemScrollController, this.itemScrollController,
ItemPositionsListener? itemPositionsListener, ItemPositionsListener? itemPositionsListener,
this.initialScrollIndex = 0, this.initialScrollIndex = 0,
@@ -77,9 +76,7 @@ class ScrollablePositionedList extends StatefulWidget {
this.minCacheExtent, this.minCacheExtent,
this.findChildIndexCallback, this.findChildIndexCallback,
this.keyboardDismissBehavior, this.keyboardDismissBehavior,
}) : assert(separatorBuilder != null, 'seperatorBuilder cannot be null'), }) : itemPositionsNotifier = itemPositionsListener as ItemPositionsNotifier?;
itemPositionsNotifier = itemPositionsListener as ItemPositionsNotifier?,
super(key: key);
/// Called to find the new index of a child based on its key in case of /// Called to find the new index of a child based on its key in case of
/// reordering. /// reordering.
@@ -280,7 +277,7 @@ class _ScrollablePositionedListState extends State<ScrollablePositionedList>
void initState() { void initState() {
super.initState(); super.initState();
final ItemPosition? initialPosition = final ItemPosition? initialPosition =
PageStorage.of(context)!.readState(context); PageStorage.of(context).readState(context);
primary primary
..target = initialPosition?.index ?? widget.initialScrollIndex ..target = initialPosition?.index ?? widget.initialScrollIndex
..alignment = initialPosition?.itemLeadingEdge ?? widget.initialAlignment; ..alignment = initialPosition?.itemLeadingEdge ?? widget.initialAlignment;
@@ -572,7 +569,7 @@ class _ScrollablePositionedListState extends State<ScrollablePositionedList>
.where((ItemPosition position) => .where((ItemPosition position) =>
position.itemLeadingEdge < 1 && position.itemTrailingEdge > 0); position.itemLeadingEdge < 1 && position.itemTrailingEdge > 0);
if (itemPositions.isNotEmpty) { if (itemPositions.isNotEmpty) {
PageStorage.of(context)!.writeState( PageStorage.of(context).writeState(
context, context,
itemPositions.reduce((value, element) => itemPositions.reduce((value, element) =>
value.itemLeadingEdge < element.itemLeadingEdge ? value : element), value.itemLeadingEdge < element.itemLeadingEdge ? value : element),
@@ -19,24 +19,15 @@ import 'package:flutter/widgets.dart';
class UnboundedViewport extends Viewport { class UnboundedViewport extends Viewport {
/// {@macro unbounded_viewport} /// {@macro unbounded_viewport}
UnboundedViewport({ UnboundedViewport({
Key? key, super.key,
AxisDirection axisDirection = AxisDirection.down, super.axisDirection,
AxisDirection? crossAxisDirection, super.crossAxisDirection,
double anchor = 0.0, double anchor = 0.0,
required ViewportOffset offset, required super.offset,
Key? center, super.center,
double? cacheExtent, super.cacheExtent,
List<Widget> slivers = const <Widget>[], super.slivers,
}) : _anchor = anchor, }) : _anchor = anchor;
super(
key: key,
axisDirection: axisDirection,
crossAxisDirection: crossAxisDirection,
offset: offset,
center: center,
cacheExtent: cacheExtent,
slivers: slivers,
);
// [Viewport] enforces constraints on [Viewport.anchor], so we need our own // [Viewport] enforces constraints on [Viewport.anchor], so we need our own
// version. // version.
@@ -68,22 +59,14 @@ class UnboundedViewport extends Viewport {
class UnboundedRenderViewport extends RenderViewport { class UnboundedRenderViewport extends RenderViewport {
/// Creates a viewport for [RenderSliver] objects. /// Creates a viewport for [RenderSliver] objects.
UnboundedRenderViewport({ UnboundedRenderViewport({
AxisDirection axisDirection = AxisDirection.down, super.axisDirection,
required AxisDirection crossAxisDirection, required super.crossAxisDirection,
required ViewportOffset offset, required super.offset,
double anchor = 0.0, double anchor = 0.0,
List<RenderSliver>? children, super.children,
RenderSliver? center, super.center,
double? cacheExtent, super.cacheExtent,
}) : _anchor = anchor, }) : _anchor = anchor;
super(
axisDirection: axisDirection,
crossAxisDirection: crossAxisDirection,
offset: offset,
center: center,
cacheExtent: cacheExtent,
children: children,
);
static const int _maxLayoutCycles = 10; static const int _maxLayoutCycles = 10;
+16 -1
View File
@@ -46,6 +46,21 @@ dependencies:
video_thumbnail: ^0.5.0 video_thumbnail: ^0.5.0
flutter: flutter:
plugin:
platforms:
android:
default_package: stream_chat_flutter
ios:
default_package: stream_chat_flutter
windows:
default_package: stream_chat_flutter
linux:
default_package: stream_chat_flutter
macos:
default_package: stream_chat_flutter
web:
default_package: stream_chat_flutter
assets: assets:
- images/ - images/
- svgs/ - svgs/
@@ -54,7 +69,7 @@ flutter:
uses-material-design: true uses-material-design: true
dev_dependencies: dev_dependencies:
dart_code_metrics: ^5.7.0 dart_code_metrics: ^5.7.2
flutter_test: flutter_test:
sdk: flutter sdk: flutter
golden_toolkit: ^0.15.0 golden_toolkit: ^0.15.0
@@ -3,7 +3,6 @@ import 'dart:math';
import 'package:stream_chat/stream_chat.dart' hide Success; import 'package:stream_chat/stream_chat.dart' hide Success;
import 'package:stream_chat_flutter_core/src/paged_value_notifier.dart'; import 'package:stream_chat_flutter_core/src/paged_value_notifier.dart';
import 'package:stream_chat_flutter_core/src/stream_channel_list_event_handler.dart'; import 'package:stream_chat_flutter_core/src/stream_channel_list_event_handler.dart';
/// The default channel page limit to load. /// The default channel page limit to load.
@@ -21,7 +21,7 @@ dependencies:
dev_dependencies: dev_dependencies:
build_runner: ^2.3.3 build_runner: ^2.3.3
dart_code_metrics: ^5.7.0 dart_code_metrics: ^5.7.2
fake_async: ^1.2.0 fake_async: ^1.2.0
flutter_test: flutter_test:
sdk: flutter sdk: flutter
@@ -17,6 +17,22 @@ dependencies:
stream_chat_flutter: ^5.3.0 stream_chat_flutter: ^5.3.0
dev_dependencies: dev_dependencies:
dart_code_metrics: ^4.16.0 dart_code_metrics: ^5.7.2
flutter_test: flutter_test:
sdk: flutter sdk: flutter
flutter:
plugin:
platforms:
android:
default_package: stream_chat_localizations
ios:
default_package: stream_chat_localizations
windows:
default_package: stream_chat_localizations
linux:
default_package: stream_chat_localizations
macos:
default_package: stream_chat_localizations
web:
default_package: stream_chat_localizations
@@ -1,5 +1,6 @@
## Upcoming ## Upcoming
- Updated `drift` to `^2.7.0`.
- Updated dependencies to resolvable versions. - Updated dependencies to resolvable versions.
## 5.1.0 ## 5.1.0
@@ -3,7 +3,6 @@ targets:
builders: builders:
drift_dev: drift_dev:
options: options:
generate_connect_constructor: true
data_class_to_companions: false data_class_to_companions: false
apply_converters_on_variables: true apply_converters_on_variables: true
generate_values_in_copy_with: true generate_values_in_copy_with: true
@@ -6,7 +6,21 @@ import 'package:drift/drift.dart';
/// by the sqlite backend. /// by the sqlite backend.
class ListConverter<T> extends TypeConverter<List<T>, String> { class ListConverter<T> extends TypeConverter<List<T>, String> {
@override @override
List<T>? mapToDart(String? fromDb) { List<T> fromSql(String fromDb) {
return List<T>.from(jsonDecode(fromDb) ?? []);
}
@override
String toSql(List<T> value) {
return jsonEncode(value);
}
}
/// Maps a nullable [List] of type [T] into a nullable [String] understood
/// by the sqlite backend.
class NullableListConverter<T> extends TypeConverter<List<T>?, String?> {
@override
List<T>? fromSql(String? fromDb) {
if (fromDb == null) { if (fromDb == null) {
return null; return null;
} }
@@ -14,7 +28,7 @@ class ListConverter<T> extends TypeConverter<List<T>, String> {
} }
@override @override
String? mapToSql(List<T>? value) { String? toSql(List<T>? value) {
if (value == null) { if (value == null) {
return null; return null;
} }
@@ -6,7 +6,21 @@ import 'package:drift/drift.dart';
/// by the sqlite backend. /// by the sqlite backend.
class MapConverter<T> extends TypeConverter<Map<String, T>, String> { class MapConverter<T> extends TypeConverter<Map<String, T>, String> {
@override @override
Map<String, T>? mapToDart(String? fromDb) { Map<String, T> fromSql(String fromDb) {
return Map<String, T>.from(jsonDecode(fromDb) ?? {});
}
@override
String toSql(Map<String, T> value) {
return jsonEncode(value);
}
}
/// Maps a nullable [Map] of type [String], [T] into a nullable [String]
/// understood by the sqlite backend.
class NullableMapConverter<T> extends TypeConverter<Map<String, T>?, String?> {
@override
Map<String, T>? fromSql(String? fromDb) {
if (fromDb == null) { if (fromDb == null) {
return null; return null;
} }
@@ -14,7 +28,7 @@ class MapConverter<T> extends TypeConverter<Map<String, T>, String> {
} }
@override @override
String? mapToSql(Map<String, T>? value) { String? toSql(Map<String, T>? value) {
if (value == null) { if (value == null) {
return null; return null;
} }
@@ -6,7 +6,7 @@ import 'package:stream_chat/stream_chat.dart';
class MessageSendingStatusConverter class MessageSendingStatusConverter
extends TypeConverter<MessageSendingStatus, int> { extends TypeConverter<MessageSendingStatus, int> {
@override @override
MessageSendingStatus? mapToDart(int? fromDb) { MessageSendingStatus fromSql(int fromDb) {
switch (fromDb) { switch (fromDb) {
case 0: case 0:
return MessageSendingStatus.sending; return MessageSendingStatus.sending;
@@ -22,13 +22,12 @@ class MessageSendingStatusConverter
return MessageSendingStatus.deleting; return MessageSendingStatus.deleting;
case 6: case 6:
return MessageSendingStatus.failed_delete; return MessageSendingStatus.failed_delete;
default:
return null;
} }
return MessageSendingStatus.sending;
} }
@override @override
int? mapToSql(MessageSendingStatus? value) { int toSql(MessageSendingStatus value) {
switch (value) { switch (value) {
case MessageSendingStatus.sending: case MessageSendingStatus.sending:
return 0; return 0;
@@ -44,8 +43,6 @@ class MessageSendingStatusConverter
return 5; return 5;
case MessageSendingStatus.failed_delete: case MessageSendingStatus.failed_delete:
return 6; return 6;
default:
return null;
} }
} }
} }
@@ -2,10 +2,7 @@
part of 'channel_dao.dart'; part of 'channel_dao.dart';
// ************************************************************************** // ignore_for_file: type=lint
// DaoGenerator
// **************************************************************************
mixin _$ChannelDaoMixin on DatabaseAccessor<DriftChatDatabase> { mixin _$ChannelDaoMixin on DatabaseAccessor<DriftChatDatabase> {
$ChannelsTable get channels => attachedDatabase.channels; $ChannelsTable get channels => attachedDatabase.channels;
$UsersTable get users => attachedDatabase.users; $UsersTable get users => attachedDatabase.users;
@@ -2,10 +2,7 @@
part of 'channel_query_dao.dart'; part of 'channel_query_dao.dart';
// ************************************************************************** // ignore_for_file: type=lint
// DaoGenerator
// **************************************************************************
mixin _$ChannelQueryDaoMixin on DatabaseAccessor<DriftChatDatabase> { mixin _$ChannelQueryDaoMixin on DatabaseAccessor<DriftChatDatabase> {
$ChannelQueriesTable get channelQueries => attachedDatabase.channelQueries; $ChannelQueriesTable get channelQueries => attachedDatabase.channelQueries;
$ChannelsTable get channels => attachedDatabase.channels; $ChannelsTable get channels => attachedDatabase.channels;
@@ -2,10 +2,7 @@
part of 'connection_event_dao.dart'; part of 'connection_event_dao.dart';
// ************************************************************************** // ignore_for_file: type=lint
// DaoGenerator
// **************************************************************************
mixin _$ConnectionEventDaoMixin on DatabaseAccessor<DriftChatDatabase> { mixin _$ConnectionEventDaoMixin on DatabaseAccessor<DriftChatDatabase> {
$ConnectionEventsTable get connectionEvents => $ConnectionEventsTable get connectionEvents =>
attachedDatabase.connectionEvents; attachedDatabase.connectionEvents;
@@ -2,11 +2,9 @@
part of 'member_dao.dart'; part of 'member_dao.dart';
// ************************************************************************** // ignore_for_file: type=lint
// DaoGenerator
// **************************************************************************
mixin _$MemberDaoMixin on DatabaseAccessor<DriftChatDatabase> { mixin _$MemberDaoMixin on DatabaseAccessor<DriftChatDatabase> {
$ChannelsTable get channels => attachedDatabase.channels;
$MembersTable get members => attachedDatabase.members; $MembersTable get members => attachedDatabase.members;
$UsersTable get users => attachedDatabase.users; $UsersTable get users => attachedDatabase.users;
} }
@@ -2,11 +2,9 @@
part of 'message_dao.dart'; part of 'message_dao.dart';
// ************************************************************************** // ignore_for_file: type=lint
// DaoGenerator
// **************************************************************************
mixin _$MessageDaoMixin on DatabaseAccessor<DriftChatDatabase> { mixin _$MessageDaoMixin on DatabaseAccessor<DriftChatDatabase> {
$ChannelsTable get channels => attachedDatabase.channels;
$MessagesTable get messages => attachedDatabase.messages; $MessagesTable get messages => attachedDatabase.messages;
$UsersTable get users => attachedDatabase.users; $UsersTable get users => attachedDatabase.users;
} }
@@ -2,11 +2,9 @@
part of 'pinned_message_dao.dart'; part of 'pinned_message_dao.dart';
// ************************************************************************** // ignore_for_file: type=lint
// DaoGenerator
// **************************************************************************
mixin _$PinnedMessageDaoMixin on DatabaseAccessor<DriftChatDatabase> { mixin _$PinnedMessageDaoMixin on DatabaseAccessor<DriftChatDatabase> {
$ChannelsTable get channels => attachedDatabase.channels;
$PinnedMessagesTable get pinnedMessages => attachedDatabase.pinnedMessages; $PinnedMessagesTable get pinnedMessages => attachedDatabase.pinnedMessages;
$UsersTable get users => attachedDatabase.users; $UsersTable get users => attachedDatabase.users;
} }
@@ -2,11 +2,10 @@
part of 'pinned_message_reaction_dao.dart'; part of 'pinned_message_reaction_dao.dart';
// ************************************************************************** // ignore_for_file: type=lint
// DaoGenerator
// **************************************************************************
mixin _$PinnedMessageReactionDaoMixin on DatabaseAccessor<DriftChatDatabase> { mixin _$PinnedMessageReactionDaoMixin on DatabaseAccessor<DriftChatDatabase> {
$ChannelsTable get channels => attachedDatabase.channels;
$PinnedMessagesTable get pinnedMessages => attachedDatabase.pinnedMessages;
$PinnedMessageReactionsTable get pinnedMessageReactions => $PinnedMessageReactionsTable get pinnedMessageReactions =>
attachedDatabase.pinnedMessageReactions; attachedDatabase.pinnedMessageReactions;
$UsersTable get users => attachedDatabase.users; $UsersTable get users => attachedDatabase.users;
@@ -2,11 +2,10 @@
part of 'reaction_dao.dart'; part of 'reaction_dao.dart';
// ************************************************************************** // ignore_for_file: type=lint
// DaoGenerator
// **************************************************************************
mixin _$ReactionDaoMixin on DatabaseAccessor<DriftChatDatabase> { mixin _$ReactionDaoMixin on DatabaseAccessor<DriftChatDatabase> {
$ChannelsTable get channels => attachedDatabase.channels;
$MessagesTable get messages => attachedDatabase.messages;
$ReactionsTable get reactions => attachedDatabase.reactions; $ReactionsTable get reactions => attachedDatabase.reactions;
$UsersTable get users => attachedDatabase.users; $UsersTable get users => attachedDatabase.users;
} }
@@ -2,11 +2,9 @@
part of 'read_dao.dart'; part of 'read_dao.dart';
// ************************************************************************** // ignore_for_file: type=lint
// DaoGenerator
// **************************************************************************
mixin _$ReadDaoMixin on DatabaseAccessor<DriftChatDatabase> { mixin _$ReadDaoMixin on DatabaseAccessor<DriftChatDatabase> {
$ChannelsTable get channels => attachedDatabase.channels;
$ReadsTable get reads => attachedDatabase.reads; $ReadsTable get reads => attachedDatabase.reads;
$UsersTable get users => attachedDatabase.users; $UsersTable get users => attachedDatabase.users;
} }
@@ -2,10 +2,7 @@
part of 'user_dao.dart'; part of 'user_dao.dart';
// ************************************************************************** // ignore_for_file: type=lint
// DaoGenerator
// **************************************************************************
mixin _$UserDaoMixin on DatabaseAccessor<DriftChatDatabase> { mixin _$UserDaoMixin on DatabaseAccessor<DriftChatDatabase> {
$UsersTable get users => attachedDatabase.users; $UsersTable get users => attachedDatabase.users;
} }
@@ -1,6 +1,5 @@
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat/stream_chat.dart';
import 'package:stream_chat_persistence/src/converter/converter.dart'; import 'package:stream_chat_persistence/src/converter/converter.dart';
import 'package:stream_chat_persistence/src/dao/dao.dart'; import 'package:stream_chat_persistence/src/dao/dao.dart';
import 'package:stream_chat_persistence/src/entity/entity.dart'; import 'package:stream_chat_persistence/src/entity/entity.dart';
@@ -37,18 +36,12 @@ part 'drift_chat_database.g.dart';
], ],
) )
class DriftChatDatabase extends _$DriftChatDatabase { class DriftChatDatabase extends _$DriftChatDatabase {
/// Creates a new moor chat database instance /// Creates a new drift chat database instance
DriftChatDatabase( DriftChatDatabase(
this._userId, this._userId,
QueryExecutor executor, QueryExecutor executor,
) : super(executor); ) : super(executor);
/// Instantiate a new database instance
DriftChatDatabase.connect(
this._userId,
DatabaseConnection connection,
) : super.connect(connection);
final String _userId; final String _userId;
/// User id to which the database is connected /// User id to which the database is connected
@@ -56,7 +49,7 @@ class DriftChatDatabase extends _$DriftChatDatabase {
// you should bump this number whenever you change or add a table definition. // you should bump this number whenever you change or add a table definition.
@override @override
int get schemaVersion => 9; int get schemaVersion => 10;
@override @override
MigrationStrategy get migration => MigrationStrategy( MigrationStrategy get migration => MigrationStrategy(
File diff suppressed because it is too large Load Diff
@@ -23,7 +23,7 @@ class SharedDB {
}) async { }) async {
final dbName = 'db_$userId'; final dbName = 'db_$userId';
if (connectionMode == ConnectionMode.background) { if (connectionMode == ConnectionMode.background) {
return DriftChatDatabase.connect( return DriftChatDatabase(
userId, userId,
DatabaseConnection.delayed(Future(() async { DatabaseConnection.delayed(Future(() async {
final isolate = await _createMoorIsolate( final isolate = await _createMoorIsolate(
@@ -34,6 +34,7 @@ class SharedDB {
})), })),
); );
} }
return DriftChatDatabase( return DriftChatDatabase(
userId, userId,
LazyDatabase( LazyDatabase(
@@ -68,7 +69,7 @@ class SharedDB {
logStatements: request.logStatements, logStatements: request.logStatements,
)); ));
final moorIsolate = DriftIsolate.inCurrent( final moorIsolate = DriftIsolate.inCurrent(
() => DatabaseConnection.fromExecutor(executor), () => DatabaseConnection(executor),
); );
request.sendMoorIsolate.send(moorIsolate); request.sendMoorIsolate.send(moorIsolate);
} }
@@ -1,5 +1,6 @@
// coverage:ignore-file // coverage:ignore-file
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
import 'package:stream_chat_persistence/src/entity/channels.dart';
/// Represents a [Members] table in [MoorChatDatabase]. /// Represents a [Members] table in [MoorChatDatabase].
@DataClassName('MemberEntity') @DataClassName('MemberEntity')
@@ -9,7 +10,7 @@ class Members extends Table {
/// The channel cid of which this user is part of /// The channel cid of which this user is part of
TextColumn get channelCid => TextColumn get channelCid =>
text().customConstraint('REFERENCES channels(cid) ON DELETE CASCADE')(); text().references(Channels, #cid, onDelete: KeyAction.cascade)();
/// The role of the user in the channel /// The role of the user in the channel
TextColumn get channelRole => text().nullable()(); TextColumn get channelRole => text().nullable()();
@@ -3,6 +3,7 @@ import 'package:drift/drift.dart';
import 'package:stream_chat_persistence/src/converter/list_converter.dart'; import 'package:stream_chat_persistence/src/converter/list_converter.dart';
import 'package:stream_chat_persistence/src/converter/map_converter.dart'; import 'package:stream_chat_persistence/src/converter/map_converter.dart';
import 'package:stream_chat_persistence/src/converter/message_sending_status_converter.dart'; import 'package:stream_chat_persistence/src/converter/message_sending_status_converter.dart';
import 'package:stream_chat_persistence/src/entity/channels.dart';
/// Represents a [Messages] table in [MoorChatDatabase]. /// Represents a [Messages] table in [MoorChatDatabase].
@DataClassName('MessageEntity') @DataClassName('MessageEntity')
@@ -78,10 +79,11 @@ class Messages extends Table {
/// The channel cid of which this message is part of /// The channel cid of which this message is part of
TextColumn get channelCid => TextColumn get channelCid =>
text().customConstraint('REFERENCES channels(cid) ON DELETE CASCADE')(); text().references(Channels, #cid, onDelete: KeyAction.cascade)();
/// A Map of [messageText] translations. /// A Map of [messageText] translations.
TextColumn get i18n => text().nullable().map(MapConverter<String>())(); TextColumn get i18n =>
text().nullable().map(NullableMapConverter<String>())();
/// Message custom extraData /// Message custom extraData
TextColumn get extraData => text().nullable().map(MapConverter<Object?>())(); TextColumn get extraData => text().nullable().map(MapConverter<Object?>())();
@@ -1,6 +1,6 @@
// coverage:ignore-file // coverage:ignore-file
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
import 'package:stream_chat_persistence/src/entity/pinned_messages.dart';
import 'package:stream_chat_persistence/src/entity/reactions.dart'; import 'package:stream_chat_persistence/src/entity/reactions.dart';
/// Represents a [PinnedMessageReactions] table in [MoorChatDatabase]. /// Represents a [PinnedMessageReactions] table in [MoorChatDatabase].
@@ -8,6 +8,6 @@ import 'package:stream_chat_persistence/src/entity/reactions.dart';
class PinnedMessageReactions extends Reactions { class PinnedMessageReactions extends Reactions {
/// The messageId to which the reaction belongs /// The messageId to which the reaction belongs
@override @override
TextColumn get messageId => text() TextColumn get messageId =>
.customConstraint('REFERENCES pinned_messages(id) ON DELETE CASCADE')(); text().references(PinnedMessages, #id, onDelete: KeyAction.cascade)();
} }
@@ -1,6 +1,5 @@
// coverage:ignore-file // coverage:ignore-file
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
import 'package:stream_chat_persistence/src/entity/messages.dart'; import 'package:stream_chat_persistence/src/entity/messages.dart';
/// Represents a [PinnedMessages] table in [MoorChatDatabase]. /// Represents a [PinnedMessages] table in [MoorChatDatabase].
@@ -1,6 +1,7 @@
// coverage:ignore-file // coverage:ignore-file
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
import 'package:stream_chat_persistence/src/converter/map_converter.dart'; import 'package:stream_chat_persistence/src/converter/map_converter.dart';
import 'package:stream_chat_persistence/src/entity/messages.dart';
/// Represents a [Reactions] table in [MoorChatDatabase]. /// Represents a [Reactions] table in [MoorChatDatabase].
@DataClassName('ReactionEntity') @DataClassName('ReactionEntity')
@@ -10,7 +11,7 @@ class Reactions extends Table {
/// The messageId to which the reaction belongs /// The messageId to which the reaction belongs
TextColumn get messageId => TextColumn get messageId =>
text().customConstraint('REFERENCES messages(id) ON DELETE CASCADE')(); text().references(Messages, #id, onDelete: KeyAction.cascade)();
/// The type of the reaction /// The type of the reaction
TextColumn get type => text()(); TextColumn get type => text()();
@@ -1,5 +1,6 @@
// coverage:ignore-file // coverage:ignore-file
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
import 'package:stream_chat_persistence/src/entity/channels.dart';
/// Represents a [Reads] table in [MoorChatDatabase]. /// Represents a [Reads] table in [MoorChatDatabase].
@DataClassName('ReadEntity') @DataClassName('ReadEntity')
@@ -12,7 +13,7 @@ class Reads extends Table {
/// The channel cid of which this read belongs /// The channel cid of which this read belongs
TextColumn get channelCid => TextColumn get channelCid =>
text().customConstraint('REFERENCES channels(cid) ON DELETE CASCADE')(); text().references(Channels, #cid, onDelete: KeyAction.cascade)();
/// Number of unread messages /// Number of unread messages
IntColumn get unreadMessages => integer().withDefault(const Constant(0))(); IntColumn get unreadMessages => integer().withDefault(const Constant(0))();
@@ -10,7 +10,7 @@ environment:
flutter: ">=1.17.0" flutter: ">=1.17.0"
dependencies: dependencies:
drift: ^1.7.1 drift: ^2.7.0
flutter: flutter:
sdk: flutter sdk: flutter
logging: ^1.0.1 logging: ^1.0.1
@@ -23,8 +23,8 @@ dependencies:
dev_dependencies: dev_dependencies:
build_runner: ^2.3.3 build_runner: ^2.3.3
dart_code_metrics: ^4.18.0 dart_code_metrics: ^5.7.2
drift_dev: ^1.7.1 drift_dev: ^2.7.0
flutter_test: flutter_test:
sdk: flutter sdk: flutter
mocktail: ^0.3.0 mocktail: ^0.3.0
@@ -4,50 +4,91 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:stream_chat_persistence/src/converter/list_converter.dart'; import 'package:stream_chat_persistence/src/converter/list_converter.dart';
void main() { void main() {
group('mapToDart', () { group('ListConverter', () {
final listConverter = ListConverter<String>(); final listConverter = ListConverter<String>();
test('should return null if nothing is provided', () { group('fromSql', () {
final res = listConverter.mapToDart(null); test('should throw type error if the provided json is not a list', () {
expect(res, isNull); final json = {'test_key': 'testData'};
}); expect(
() => listConverter.fromSql(jsonEncode(json)),
throwsA(isA<TypeError>()),
);
});
test('should throw type error if the provided json is not a list', () { test(
final json = {'test_key': 'testData'}; 'should throw type error if the provided json is not a list of String',
expect(
() => listConverter.mapToDart(jsonEncode(json)),
throwsA(isA<TypeError>()),
);
});
test('should throw type error if the provided json is not a list of String',
() { () {
final json = [22, 33, 44]; final json = [22, 33, 44];
expect( expect(
() => listConverter.mapToDart(jsonEncode(json)), () => listConverter.fromSql(jsonEncode(json)),
throwsA(isA<TypeError>()), throwsA(isA<TypeError>()),
);
},
); );
test('should return list of String if json data list is provided', () {
final data = ['data1', 'data2', 'data3'];
final res = listConverter.fromSql(jsonEncode(data));
expect(res.length, data.length);
});
}); });
test('should return list of String if json data list is provided', () { group('toSql', () {
final data = ['data1', 'data2', 'data3']; test('should return json string if data list is provided', () {
final res = listConverter.mapToDart(jsonEncode(data)); final data = ['data1', 'data2', 'data3'];
expect(res!.length, data.length); final res = listConverter.toSql(data);
expect(res, jsonEncode(data));
});
}); });
}); });
group('mapToSql', () { group('NullableListConverter', () {
final listConverter = ListConverter<String>(); final listConverter = NullableListConverter<String>();
test('should return null if nothing is provided', () { group('fromSql', () {
final res = listConverter.mapToSql(null); test('should return null if nothing is provided', () {
expect(res, isNull); final res = listConverter.fromSql(null);
expect(res, isNull);
});
test('should throw type error if the provided json is not a list', () {
final json = {'test_key': 'testData'};
expect(
() => listConverter.fromSql(jsonEncode(json)),
throwsA(isA<TypeError>()),
);
});
test(
'should throw type error if the provided json is not a list of String',
() {
final json = [22, 33, 44];
expect(
() => listConverter.fromSql(jsonEncode(json)),
throwsA(isA<TypeError>()),
);
},
);
test('should return list of String if json data list is provided', () {
final data = ['data1', 'data2', 'data3'];
final res = listConverter.fromSql(jsonEncode(data));
expect(res!.length, data.length);
});
}); });
test('should return json string if data list is provided', () { group('toSql', () {
final data = ['data1', 'data2', 'data3']; test('should return null if nothing is provided', () {
final res = listConverter.mapToSql(data); final res = listConverter.toSql(null);
expect(res, jsonEncode(data)); expect(res, isNull);
});
test('should return json string if data list is provided', () {
final data = ['data1', 'data2', 'data3'];
final res = listConverter.toSql(data);
expect(res, jsonEncode(data));
});
}); });
}); });
} }
@@ -4,61 +4,109 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:stream_chat_persistence/src/converter/map_converter.dart'; import 'package:stream_chat_persistence/src/converter/map_converter.dart';
void main() { void main() {
group('mapToDart', () { group('MapConverter', () {
final mapConverter = MapConverter<String>(); final mapConverter = MapConverter<String>();
test('should return null if nothing is provided', () { group('fromSql', () {
final res = mapConverter.mapToDart(null); test('should throw type error if the provided json is not a map', () {
expect(res, isNull); const json = ['testData1', 'testData2', 'testData3'];
});
test('should throw type error if the provided json is not a map', () {
const json = ['testData1', 'testData2', 'testData3'];
expect(
() => mapConverter.mapToDart(jsonEncode(json)),
throwsA(isA<TypeError>()),
);
});
test(
'should throw type error if the provided json is not a '
'map of String, String',
() {
const json = {'test_key': 22, 'test_key2': 33, 'test_key3': 44};
expect( expect(
() => mapConverter.mapToDart(jsonEncode(json)), () => mapConverter.fromSql(jsonEncode(json)),
throwsA(isA<TypeError>()), throwsA(isA<TypeError>()),
); );
}, });
);
test('should return map of String, String if json data is provided', () { test(
const data = { 'should throw type error if the provided json is not a '
'test_key': 'testValue', 'map of String, String',
'test_key2': 'testValue2', () {
'test_key3': 'testValue3', const json = {'test_key': 22, 'test_key2': 33, 'test_key3': 44};
}; expect(
final res = mapConverter.mapToDart(jsonEncode(data)); () => mapConverter.fromSql(jsonEncode(json)),
expect(res, data); throwsA(isA<TypeError>()),
);
},
);
test('should return map of String, String if json data is provided', () {
const data = {
'test_key': 'testValue',
'test_key2': 'testValue2',
'test_key3': 'testValue3',
};
final res = mapConverter.fromSql(jsonEncode(data));
expect(res, data);
});
});
group('toSql', () {
test('should return json string if data map is provided', () {
const data = {
'test_key': 'testValue',
'test_key2': 'testValue2',
'test_key3': 'testValue3',
};
final res = mapConverter.toSql(data);
expect(res, jsonEncode(data));
});
}); });
}); });
group('mapToSql', () { group('NullableMapConverter', () {
final mapConverter = MapConverter<String>(); final mapConverter = NullableMapConverter<String>();
test('should return null if nothing is provided', () { group('fromSql', () {
final res = mapConverter.mapToSql(null); test('should return null if nothing is provided', () {
expect(res, isNull); final res = mapConverter.fromSql(null);
expect(res, isNull);
});
test('should throw type error if the provided json is not a map', () {
const json = ['testData1', 'testData2', 'testData3'];
expect(
() => mapConverter.fromSql(jsonEncode(json)),
throwsA(isA<TypeError>()),
);
});
test(
'should throw type error if the provided json is not a '
'map of String, String',
() {
const json = {'test_key': 22, 'test_key2': 33, 'test_key3': 44};
expect(
() => mapConverter.fromSql(jsonEncode(json)),
throwsA(isA<TypeError>()),
);
},
);
test('should return map of String, String if json data is provided', () {
const data = {
'test_key': 'testValue',
'test_key2': 'testValue2',
'test_key3': 'testValue3',
};
final res = mapConverter.fromSql(jsonEncode(data));
expect(res, data);
});
}); });
test('should return json string if data map is provided', () { group('toSql', () {
const data = { test('should return null if nothing is provided', () {
'test_key': 'testValue', final res = mapConverter.toSql(null);
'test_key2': 'testValue2', expect(res, isNull);
'test_key3': 'testValue3', });
};
final res = mapConverter.mapToSql(data); test('should return json string if data map is provided', () {
expect(res, jsonEncode(data)); const data = {
'test_key': 'testValue',
'test_key2': 'testValue2',
'test_key3': 'testValue3',
};
final res = mapConverter.toSql(data);
expect(res, jsonEncode(data));
});
}); });
}); });
} }
@@ -3,31 +3,21 @@ import 'package:stream_chat/stream_chat.dart';
import 'package:stream_chat_persistence/src/converter/message_sending_status_converter.dart'; import 'package:stream_chat_persistence/src/converter/message_sending_status_converter.dart';
void main() { void main() {
group('mapToDart', () { group('fromSql', () {
final statusConverter = MessageSendingStatusConverter(); final statusConverter = MessageSendingStatusConverter();
test('should return null if nothing is provided', () {
final res = statusConverter.mapToDart(null);
expect(res, isNull);
});
test('should return expected status if status code is provided', () { test('should return expected status if status code is provided', () {
final res = statusConverter.mapToDart(3); final res = statusConverter.fromSql(6);
expect(res, MessageSendingStatus.updating); expect(res, MessageSendingStatus.failed_delete);
}); });
}); });
group('mapToSql', () { group('toSql', () {
final statusConverter = MessageSendingStatusConverter(); final statusConverter = MessageSendingStatusConverter();
test('should return null if nothing is provided', () {
final res = statusConverter.mapToSql(null);
expect(res, isNull);
});
test('should return expected code if the status is provided', () { test('should return expected code if the status is provided', () {
final res = statusConverter.mapToSql(MessageSendingStatus.updating); final res = statusConverter.toSql(MessageSendingStatus.failed_delete);
expect(res, 3); expect(res, 6);
}); });
}); });
} }
@@ -5,7 +5,7 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:stream_chat_persistence/src/db/drift_chat_database.dart'; import 'package:stream_chat_persistence/src/db/drift_chat_database.dart';
DatabaseConnection _backgroundConnection() => DatabaseConnection _backgroundConnection() =>
DatabaseConnection.fromExecutor(NativeDatabase.memory()); DatabaseConnection(NativeDatabase.memory());
void main() { void main() {
test( test(
@@ -30,7 +30,7 @@ void main() {
final isolate = await DriftIsolate.spawn(_backgroundConnection); final isolate = await DriftIsolate.spawn(_backgroundConnection);
final connection = DatabaseConnection.delayed(isolate.connect()); final connection = DatabaseConnection.delayed(isolate.connect());
final database = DriftChatDatabase.connect(userId, connection); final database = DriftChatDatabase(userId, connection);
expect(database, isNotNull); expect(database, isNotNull);
expect(database.userId, userId); expect(database.userId, userId);