feat: update dependencies, ui and linting
This commit is contained in:
@@ -1,60 +1,29 @@
|
|||||||
include: package:pedantic/analysis_options.yaml
|
# This file configures the analyzer, which statically analyzes Dart code to
|
||||||
|
# check for errors, warnings, and lints.
|
||||||
|
#
|
||||||
|
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
|
||||||
|
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
|
||||||
|
# invoked from the command line by running `flutter analyze`.
|
||||||
|
|
||||||
analyzer:
|
# The following line activates a set of recommended lints for Flutter apps,
|
||||||
exclude:
|
# packages, and plugins designed to encourage good coding practices.
|
||||||
- lib/**/*.g.dart
|
include: package:flutter_lints/flutter.yaml
|
||||||
- example/*
|
|
||||||
- test/*
|
|
||||||
|
|
||||||
linter:
|
linter:
|
||||||
|
# The lint rules applied to this project can be customized in the
|
||||||
|
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
|
||||||
|
# included above or to enable additional rules. A list of all available lints
|
||||||
|
# and their documentation is published at
|
||||||
|
# https://dart-lang.github.io/linter/lints/index.html.
|
||||||
|
#
|
||||||
|
# Instead of disabling a lint rule for the entire project in the
|
||||||
|
# section below, it can also be suppressed for a single line of code
|
||||||
|
# or a specific dart file by using the `// ignore: name_of_lint` and
|
||||||
|
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
|
||||||
|
# producing the lint.
|
||||||
rules:
|
rules:
|
||||||
# these rules are documented on and in the same order as
|
# avoid_print: false # Uncomment to disable the `avoid_print` rule
|
||||||
# the Dart Lint rules page to make maintenance easier
|
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
|
||||||
# https://github.com/dart-lang/linter/blob/master/example/all.yaml
|
|
||||||
# - always_declare_return_types
|
# Additional information about this file can be found at
|
||||||
# - always_specify_types
|
# https://dart.dev/guides/language/analysis-options
|
||||||
# - annotate_overrides
|
|
||||||
# - avoid_as
|
|
||||||
- avoid_empty_else
|
|
||||||
- avoid_init_to_null
|
|
||||||
- avoid_return_types_on_setters
|
|
||||||
- avoid_web_libraries_in_flutter
|
|
||||||
- await_only_futures
|
|
||||||
- camel_case_types
|
|
||||||
- cancel_subscriptions
|
|
||||||
- close_sinks
|
|
||||||
# - comment_references # we do not presume as to what people want to reference in their dartdocs
|
|
||||||
# - constant_identifier_names # https://github.com/dart-lang/linter/issues/204
|
|
||||||
- control_flow_in_finally
|
|
||||||
- empty_constructor_bodies
|
|
||||||
- empty_statements
|
|
||||||
- hash_and_equals
|
|
||||||
- implementation_imports
|
|
||||||
# - invariant_booleans
|
|
||||||
# - iterable_contains_unrelated_type
|
|
||||||
- library_names
|
|
||||||
# - library_prefixes
|
|
||||||
# - list_remove_unrelated_type
|
|
||||||
# - literal_only_boolean_expressions
|
|
||||||
- non_constant_identifier_names
|
|
||||||
# - one_member_abstracts
|
|
||||||
# - only_throw_errors
|
|
||||||
# - overridden_fields
|
|
||||||
- package_names
|
|
||||||
- package_prefixed_library_names
|
|
||||||
- prefer_is_not_empty
|
|
||||||
# - prefer_mixin # https://github.com/dart-lang/language/issues/32
|
|
||||||
- slash_for_doc_comments
|
|
||||||
# - sort_constructors_first
|
|
||||||
# - sort_unnamed_constructors_first
|
|
||||||
# - super_goes_last # no longer needed w/ Dart 2
|
|
||||||
- test_types_in_equals
|
|
||||||
- throw_in_finally
|
|
||||||
# - type_annotate_public_apis # subset of always_specify_types
|
|
||||||
- type_init_formals
|
|
||||||
# - unawaited_futures
|
|
||||||
- unnecessary_brace_in_string_interps
|
|
||||||
- unnecessary_getters_setters
|
|
||||||
- unnecessary_statements
|
|
||||||
- unrelated_type_equality_checks
|
|
||||||
- valid_regexps
|
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart' show Channel;
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'
|
||||||
|
show Channel;
|
||||||
|
|
||||||
import 'package:imessage/utils.dart';
|
import 'package:imessage/utils.dart';
|
||||||
|
|
||||||
class ChannelImage extends StatelessWidget {
|
class ChannelImage extends StatelessWidget {
|
||||||
const ChannelImage({Key? key, required this.channel, required this.size})
|
const ChannelImage({
|
||||||
: super(key: key);
|
Key? key,
|
||||||
|
required this.channel,
|
||||||
|
required this.size,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
final Channel channel;
|
final Channel channel;
|
||||||
final double size;
|
final double size;
|
||||||
|
|||||||
@@ -2,12 +2,13 @@ import 'package:flutter/cupertino.dart';
|
|||||||
import 'package:imessage/channel_preview.dart';
|
import 'package:imessage/channel_preview.dart';
|
||||||
import 'package:imessage/message_page.dart';
|
import 'package:imessage/message_page.dart';
|
||||||
import 'package:animations/animations.dart';
|
import 'package:animations/animations.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart'
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'
|
||||||
show Channel, StreamChannel;
|
show Channel, StreamChannel;
|
||||||
|
|
||||||
class ChannelListView extends StatelessWidget {
|
class ChannelListView extends StatelessWidget {
|
||||||
const ChannelListView({Key? key, required this.channels}) : super(key: key);
|
const ChannelListView({Key? key, required this.channels}) : super(key: key);
|
||||||
final List<Channel> channels;
|
final List<Channel> channels;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
channels.removeWhere((channel) => channel.lastMessageAt == null);
|
channels.removeWhere((channel) => channel.lastMessageAt == null);
|
||||||
@@ -27,7 +28,7 @@ class ChannelListView extends StatelessWidget {
|
|||||||
PageRouteBuilder(
|
PageRouteBuilder(
|
||||||
pageBuilder: (_, __, ___) => StreamChannel(
|
pageBuilder: (_, __, ___) => StreamChannel(
|
||||||
channel: channels[index],
|
channel: channels[index],
|
||||||
child: MessagePage(),
|
child: const MessagePage(),
|
||||||
),
|
),
|
||||||
transitionsBuilder: (
|
transitionsBuilder: (
|
||||||
_,
|
_,
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart' show Channel;
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'
|
||||||
|
show Channel;
|
||||||
|
|
||||||
class ChannelNameText extends StatelessWidget {
|
class ChannelNameText extends StatelessWidget {
|
||||||
const ChannelNameText({
|
const ChannelNameText({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.channel,
|
required this.channel,
|
||||||
this.size = 17,
|
this.size = 17,
|
||||||
|
this.fontWeight,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
final Channel channel;
|
final Channel channel;
|
||||||
final double size;
|
final double size;
|
||||||
|
final FontWeight? fontWeight;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@@ -17,7 +20,7 @@ class ChannelNameText extends StatelessWidget {
|
|||||||
channel.extraData['name'] as String? ?? 'No name',
|
channel.extraData['name'] as String? ?? 'No name',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: size,
|
fontSize: size,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: fontWeight,
|
||||||
color: CupertinoColors.black,
|
color: CupertinoColors.black,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -7,8 +7,11 @@ class ChannelPageAppBar extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return CupertinoSliverNavigationBar(
|
return const CupertinoSliverNavigationBar(
|
||||||
largeTitle: Text('Messages'),
|
largeTitle: Text(
|
||||||
|
'Messages',
|
||||||
|
style: TextStyle(letterSpacing: -1.3),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ import 'package:flutter/cupertino.dart';
|
|||||||
import 'package:imessage/channel_image.dart';
|
import 'package:imessage/channel_image.dart';
|
||||||
import 'package:imessage/channel_name_text.dart';
|
import 'package:imessage/channel_name_text.dart';
|
||||||
import 'package:imessage/utils.dart';
|
import 'package:imessage/utils.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart' show Channel;
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'
|
||||||
|
show Channel;
|
||||||
|
|
||||||
import 'utils.dart';
|
import 'utils.dart';
|
||||||
|
|
||||||
@@ -23,7 +24,7 @@ class ChannelPreview extends StatelessWidget {
|
|||||||
: null;
|
: null;
|
||||||
|
|
||||||
final prefix = lastMessage?.attachments != null
|
final prefix = lastMessage?.attachments != null
|
||||||
? lastMessage?.attachments //TODO: ugly
|
? lastMessage?.attachments
|
||||||
.map((e) {
|
.map((e) {
|
||||||
if (e.type == 'image') {
|
if (e.type == 'image') {
|
||||||
return '📷 ';
|
return '📷 ';
|
||||||
@@ -35,13 +36,12 @@ class ChannelPreview extends StatelessWidget {
|
|||||||
.where((e) => e != null)
|
.where((e) => e != null)
|
||||||
.join(' ')
|
.join(' ')
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
behavior: HitTestBehavior.opaque,
|
behavior: HitTestBehavior.opaque,
|
||||||
child: Container(
|
child: SizedBox(
|
||||||
constraints: BoxConstraints.tightFor(
|
height: 70,
|
||||||
height: 90,
|
|
||||||
),
|
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: 8.0,
|
horizontal: 8.0,
|
||||||
@@ -50,11 +50,10 @@ class ChannelPreview extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding:
|
padding: const EdgeInsets.only(left: 16.0, right: 8.0),
|
||||||
const EdgeInsets.symmetric(vertical: 16.0, horizontal: 8.0),
|
|
||||||
child: ChannelImage(
|
child: ChannelImage(
|
||||||
channel: channel,
|
channel: channel,
|
||||||
size: 50,
|
size: 46,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
@@ -67,27 +66,29 @@ class ChannelPreview extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
padding: const EdgeInsets.symmetric(horizontal: 4.0),
|
||||||
child: ChannelNameText(
|
child: ChannelNameText(channel: channel),
|
||||||
channel: channel,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
padding: const EdgeInsets.symmetric(horizontal: 4.0),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
isSameWeek(channel.lastMessageAt!)
|
isSameWeek(channel.lastMessageAt!)
|
||||||
? formatDateSameWeek(channel.lastMessageAt!)
|
? formatDateSameWeek(channel.lastMessageAt!)
|
||||||
: formatDate(channel.lastMessageAt!),
|
: formatDate(channel.lastMessageAt!),
|
||||||
style: TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 15,
|
fontSize: 13,
|
||||||
color: CupertinoColors.systemGrey,
|
color: CupertinoColors.systemGrey,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Icon(
|
const Padding(
|
||||||
CupertinoIcons.right_chevron,
|
padding: EdgeInsets.only(left: 4.0),
|
||||||
color: CupertinoColors.systemGrey3,
|
child: Icon(
|
||||||
|
CupertinoIcons.chevron_right,
|
||||||
|
size: 16,
|
||||||
|
color: CupertinoColors.systemGrey3,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -95,19 +96,19 @@ class ChannelPreview extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(4.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
'$prefix${lastMessage?.text ?? ''}',
|
'$prefix${lastMessage?.text ?? ''}',
|
||||||
style: TextStyle(
|
style: const TextStyle(
|
||||||
fontWeight: FontWeight.normal,
|
fontWeight: FontWeight.normal,
|
||||||
color: CupertinoColors.systemGrey,
|
color: CupertinoColors.systemGrey,
|
||||||
fontSize: 16,
|
fontSize: 14,
|
||||||
),
|
),
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Divider(),
|
const Divider(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,82 +3,109 @@ import 'package:flutter/cupertino.dart';
|
|||||||
class ChatBubble extends CustomPainter {
|
class ChatBubble extends CustomPainter {
|
||||||
final Color color;
|
final Color color;
|
||||||
final Alignment? alignment;
|
final Alignment? alignment;
|
||||||
|
final bool hasTail;
|
||||||
|
|
||||||
ChatBubble({
|
ChatBubble({
|
||||||
required this.color,
|
required this.color,
|
||||||
|
required this.hasTail,
|
||||||
this.alignment,
|
this.alignment,
|
||||||
});
|
}) : paintFill = Paint()
|
||||||
|
..color = color
|
||||||
|
..style = PaintingStyle.fill;
|
||||||
|
|
||||||
final _radius = 10.0;
|
final Paint paintFill;
|
||||||
final _x = 10.0;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void paint(Canvas canvas, Size size) {
|
void paint(Canvas canvas, Size size) {
|
||||||
|
var path = Path();
|
||||||
|
const cornerSize = 18.0;
|
||||||
|
const buffer = 6.0;
|
||||||
|
const innerTailWidth = 7.0;
|
||||||
|
const innerTailHeight = 4.0;
|
||||||
if (alignment == Alignment.topRight) {
|
if (alignment == Alignment.topRight) {
|
||||||
canvas.drawRRect(
|
path.moveTo(0, cornerSize);
|
||||||
RRect.fromLTRBAndCorners(
|
path.lineTo(0, size.height - cornerSize);
|
||||||
0,
|
path.arcToPoint(Offset(cornerSize, size.height),
|
||||||
0,
|
radius: const Radius.circular(cornerSize), clockwise: false);
|
||||||
size.width - 8,
|
|
||||||
size.height,
|
if (hasTail) {
|
||||||
bottomLeft: Radius.circular(_radius),
|
path.lineTo(size.width - cornerSize - innerTailWidth, size.height);
|
||||||
topRight: Radius.circular(_radius),
|
path.arcToPoint(
|
||||||
topLeft: Radius.circular(_radius),
|
Offset(size.width - buffer - innerTailWidth,
|
||||||
),
|
size.height - innerTailHeight),
|
||||||
Paint()
|
radius: const Radius.circular(cornerSize),
|
||||||
..color = color
|
clockwise: false);
|
||||||
..style = PaintingStyle.fill);
|
|
||||||
var path = Path();
|
path.arcToPoint(Offset(size.width, size.height),
|
||||||
path.moveTo(size.width - _x, size.height - 20);
|
radius: const Radius.circular(buffer * 2), clockwise: false);
|
||||||
path.lineTo(size.width - _x, size.height);
|
|
||||||
path.lineTo(size.width, size.height);
|
path.arcToPoint(
|
||||||
canvas.clipPath(path);
|
Offset(size.width - buffer, size.height - buffer - innerTailHeight),
|
||||||
canvas.drawRRect(
|
radius: const Radius.circular(buffer + innerTailHeight),
|
||||||
RRect.fromLTRBAndCorners(
|
clockwise: true);
|
||||||
size.width - _x,
|
} else {
|
||||||
0.0,
|
path.lineTo(size.width - cornerSize, size.height);
|
||||||
size.width,
|
path.arcToPoint(Offset(size.width - buffer, size.height - cornerSize),
|
||||||
size.height,
|
radius: const Radius.circular(cornerSize), clockwise: false);
|
||||||
topRight: Radius.circular(_radius),
|
}
|
||||||
),
|
|
||||||
Paint()
|
path.lineTo(size.width - buffer, cornerSize);
|
||||||
..color = color
|
|
||||||
..style = PaintingStyle.fill);
|
path.arcToPoint(Offset(size.width - cornerSize - buffer, 0),
|
||||||
|
radius: const Radius.circular(cornerSize), clockwise: false);
|
||||||
|
|
||||||
|
path.lineTo(cornerSize, 0);
|
||||||
|
|
||||||
|
path.arcToPoint(const Offset(0, cornerSize),
|
||||||
|
radius: const Radius.circular(cornerSize), clockwise: false);
|
||||||
} else {
|
} else {
|
||||||
canvas.drawRRect(
|
path.moveTo(size.width, cornerSize);
|
||||||
RRect.fromLTRBAndCorners(
|
path.arcToPoint(Offset(size.width - cornerSize, 0),
|
||||||
_x,
|
radius: const Radius.circular(cornerSize), clockwise: false);
|
||||||
0,
|
|
||||||
size.width,
|
path.lineTo(cornerSize + buffer, 0);
|
||||||
size.height,
|
|
||||||
bottomRight: Radius.circular(_radius),
|
path.arcToPoint(const Offset(buffer, cornerSize),
|
||||||
topRight: Radius.circular(_radius),
|
radius: const Radius.circular(cornerSize), clockwise: false);
|
||||||
topLeft: Radius.circular(_radius),
|
|
||||||
),
|
if (hasTail) {
|
||||||
Paint()
|
path.lineTo(buffer, size.height - buffer - innerTailHeight);
|
||||||
..color = color
|
|
||||||
..style = PaintingStyle.fill);
|
path.arcToPoint(Offset(0, size.height),
|
||||||
var path = Path();
|
radius: const Radius.circular(buffer + innerTailHeight),
|
||||||
path.moveTo(0, size.height);
|
clockwise: true);
|
||||||
path.lineTo(_x, size.height);
|
|
||||||
path.lineTo(_x, size.height - 20);
|
path.arcToPoint(
|
||||||
canvas.clipPath(path);
|
Offset(buffer + innerTailWidth, size.height - innerTailHeight),
|
||||||
canvas.drawRRect(
|
radius: const Radius.circular(buffer * 2),
|
||||||
RRect.fromLTRBAndCorners(
|
clockwise: false);
|
||||||
0,
|
|
||||||
0.0,
|
path.arcToPoint(Offset(cornerSize + innerTailWidth, size.height),
|
||||||
_x,
|
radius: const Radius.circular(cornerSize), clockwise: false);
|
||||||
size.height,
|
} else {
|
||||||
topRight: Radius.circular(_radius),
|
path.lineTo(buffer, size.height - cornerSize);
|
||||||
),
|
path.arcToPoint(Offset(buffer + cornerSize, size.height),
|
||||||
Paint()
|
radius: const Radius.circular(cornerSize), clockwise: false);
|
||||||
..color = color
|
}
|
||||||
..style = PaintingStyle.fill);
|
|
||||||
|
path.lineTo(size.width - cornerSize, size.height);
|
||||||
|
path.arcToPoint(Offset(size.width, size.height - cornerSize),
|
||||||
|
radius: const Radius.circular(cornerSize), clockwise: false);
|
||||||
}
|
}
|
||||||
|
canvas.drawPath(
|
||||||
|
path,
|
||||||
|
paintFill,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool shouldRepaint(CustomPainter oldDelegate) {
|
bool shouldRepaint(ChatBubble oldDelegate) {
|
||||||
return true;
|
if (color != oldDelegate.color ||
|
||||||
|
alignment != oldDelegate.alignment ||
|
||||||
|
hasTail != oldDelegate.hasTail) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,20 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:intl/date_symbol_data_local.dart';
|
import 'package:intl/date_symbol_data_local.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart'
|
|
||||||
hide ChannelListView;
|
|
||||||
|
|
||||||
import 'package:imessage/channel_list_view.dart';
|
import 'package:imessage/channel_list_view.dart';
|
||||||
|
|
||||||
import 'package:imessage/channel_page_appbar.dart';
|
import 'package:imessage/channel_page_appbar.dart';
|
||||||
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||||
|
|
||||||
Future<void> main() async {
|
Future<void> main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
final client = StreamChatClient('b67pax5b2wdq', logLevel: Level.INFO); //
|
final client = StreamChatClient('b67pax5b2wdq', logLevel: Level.INFO); //
|
||||||
|
|
||||||
|
// For demonstration purposes. Fixed user and token.
|
||||||
await client.connectUser(
|
await client.connectUser(
|
||||||
User(
|
User(
|
||||||
id: 'cool-shadow-7',
|
id: 'cool-shadow-7',
|
||||||
extraData: {
|
extraData: const {
|
||||||
'image':
|
'image':
|
||||||
'https://getstream.io/random_png/?id=cool-shadow-7&name=Cool+shadow',
|
'https://getstream.io/random_png/?id=cool-shadow-7&name=Cool+shadow',
|
||||||
},
|
},
|
||||||
@@ -25,9 +26,9 @@ Future<void> main() async {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class IMessage extends StatelessWidget {
|
class IMessage extends StatelessWidget {
|
||||||
final StreamChatClient client;
|
const IMessage({Key? key, required this.client}) : super(key: key);
|
||||||
|
|
||||||
IMessage({required this.client});
|
final StreamChatClient client;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@@ -35,7 +36,7 @@ class IMessage extends StatelessWidget {
|
|||||||
return CupertinoApp(
|
return CupertinoApp(
|
||||||
title: 'Flutter Demo',
|
title: 'Flutter Demo',
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
theme: CupertinoThemeData(brightness: Brightness.light),
|
theme: const CupertinoThemeData(brightness: Brightness.light),
|
||||||
home: StreamChatCore(client: client, child: ChatLoader()),
|
home: StreamChatCore(client: client, child: ChatLoader()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -59,15 +60,15 @@ class ChatLoader extends StatelessWidget {
|
|||||||
Filter.in_('members', [user.id]),
|
Filter.in_('members', [user.id]),
|
||||||
Filter.equal('type', 'messaging'),
|
Filter.equal('type', 'messaging'),
|
||||||
]),
|
]),
|
||||||
sort: [SortOption('last_message_at')],
|
sort: const [SortOption('last_message_at')],
|
||||||
limit: 20,
|
limit: 20,
|
||||||
emptyBuilder: (BuildContext context) {
|
emptyBuilder: (BuildContext context) {
|
||||||
return Center(
|
return const Center(
|
||||||
child: Text('Looks like you are not in any channels'),
|
child: Text('Looks like you are not in any channels'),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
loadingBuilder: (BuildContext context) {
|
loadingBuilder: (BuildContext context) {
|
||||||
return Center(
|
return const Center(
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 100.0,
|
height: 100.0,
|
||||||
width: 100.0,
|
width: 100.0,
|
||||||
@@ -76,7 +77,7 @@ class ChatLoader extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
errorBuilder: (BuildContext context, dynamic error) {
|
errorBuilder: (BuildContext context, dynamic error) {
|
||||||
return Center(
|
return const Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
'Oh no, something went wrong. Please check your config.'),
|
'Oh no, something went wrong. Please check your config.'),
|
||||||
);
|
);
|
||||||
@@ -94,7 +95,7 @@ class ChatLoader extends StatelessWidget {
|
|||||||
CupertinoSliverRefreshControl(onRefresh: () async {
|
CupertinoSliverRefreshControl(onRefresh: () async {
|
||||||
return channelListController.loadData!();
|
return channelListController.loadData!();
|
||||||
}),
|
}),
|
||||||
ChannelPageAppBar(),
|
const ChannelPageAppBar(),
|
||||||
SliverPadding(
|
SliverPadding(
|
||||||
sliver: ChannelListView(channels: channels),
|
sliver: ChannelListView(channels: channels),
|
||||||
padding: const EdgeInsets.only(top: 16),
|
padding: const EdgeInsets.only(top: 16),
|
||||||
|
|||||||
@@ -9,9 +9,10 @@ class MessageHeader extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final receivedAt = DateTime.parse(rawTimeStamp);
|
final receivedAt = DateTime.parse(rawTimeStamp);
|
||||||
final textStyle = TextStyle(
|
const textStyle = TextStyle(
|
||||||
color: CupertinoColors.systemGrey,
|
color: CupertinoColors.systemGrey,
|
||||||
fontSize: 14,
|
fontWeight: FontWeight.w400,
|
||||||
|
fontSize: 11,
|
||||||
);
|
);
|
||||||
return isSameWeek(receivedAt)
|
return isSameWeek(receivedAt)
|
||||||
? Text(
|
? Text(
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import 'dart:io';
|
|||||||
|
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:image_picker/image_picker.dart';
|
import 'package:image_picker/image_picker.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart'
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'
|
||||||
show Attachment, AttachmentFile, Message, StreamChannel;
|
show Attachment, AttachmentFile, Message, StreamChannel;
|
||||||
|
|
||||||
class MessageInput extends StatefulWidget {
|
class MessageInput extends StatefulWidget {
|
||||||
@@ -59,28 +59,27 @@ class _MessageInputState extends State<MessageInput> {
|
|||||||
);
|
);
|
||||||
await channel.sendMessage(message);
|
await channel.sendMessage(message);
|
||||||
},
|
},
|
||||||
child: Padding(
|
child: const Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: EdgeInsets.all(8.0),
|
||||||
child: Icon(
|
child: Icon(
|
||||||
CupertinoIcons.camera_fill,
|
CupertinoIcons.camera_fill,
|
||||||
color: CupertinoColors.systemGrey,
|
color: CupertinoColors.systemGrey,
|
||||||
size: 35,
|
size: 32,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: CupertinoTextField(
|
child: CupertinoTextField(
|
||||||
controller: textController,
|
controller: textController,
|
||||||
|
maxLines: 10,
|
||||||
|
minLines: 1,
|
||||||
onSubmitted: (input) async {
|
onSubmitted: (input) async {
|
||||||
await sendMessage(context, input);
|
await sendMessage(context, input);
|
||||||
},
|
},
|
||||||
placeholder: 'Text Message',
|
placeholder: 'iMessage',
|
||||||
prefix: Padding(
|
padding:
|
||||||
padding: const EdgeInsets.all(8.0),
|
const EdgeInsets.symmetric(vertical: 8, horizontal: 12),
|
||||||
child: Text(
|
suffixMode: OverlayVisibilityMode.editing,
|
||||||
'',
|
|
||||||
), //trick to add padding around placeholder iMessage text
|
|
||||||
),
|
|
||||||
suffix: GestureDetector(
|
suffix: GestureDetector(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
if (textController.value.text.isNotEmpty) {
|
if (textController.value.text.isNotEmpty) {
|
||||||
@@ -88,20 +87,16 @@ class _MessageInputState extends State<MessageInput> {
|
|||||||
textController.clear();
|
textController.clear();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: Padding(
|
child: const Icon(
|
||||||
padding: const EdgeInsets.all(8.0),
|
CupertinoIcons.arrow_up_circle_fill,
|
||||||
child: Icon(
|
color: CupertinoColors.activeBlue,
|
||||||
CupertinoIcons.arrow_up_circle_fill,
|
size: 35,
|
||||||
color: CupertinoColors.activeGreen,
|
|
||||||
size: 35,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
border: Border.all(
|
border: Border.all(color: CupertinoColors.systemGrey),
|
||||||
color: CupertinoColors.systemGrey,
|
borderRadius: const BorderRadius.all(Radius.circular(35)),
|
||||||
),
|
),
|
||||||
borderRadius: BorderRadius.all(Radius.circular(35))),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import 'package:flutter/cupertino.dart';
|
|||||||
import 'package:imessage/message_header.dart';
|
import 'package:imessage/message_header.dart';
|
||||||
import 'package:imessage/message_input.dart';
|
import 'package:imessage/message_input.dart';
|
||||||
import 'package:imessage/message_widget.dart';
|
import 'package:imessage/message_widget.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart'
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'
|
||||||
show Message, StreamChatCore;
|
show Message, StreamChatCore;
|
||||||
|
|
||||||
class MessageListView extends StatelessWidget {
|
class MessageListView extends StatelessWidget {
|
||||||
@@ -16,50 +16,68 @@ class MessageListView extends StatelessWidget {
|
|||||||
(Message message) => message.createdAt.toString().substring(0, 10))
|
(Message message) => message.createdAt.toString().substring(0, 10))
|
||||||
.entries
|
.entries
|
||||||
.toList();
|
.toList();
|
||||||
return Column(
|
return Padding(
|
||||||
children: [
|
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||||
Expanded(
|
child: Column(
|
||||||
child: SizedBox(
|
children: [
|
||||||
height: MediaQuery.of(context).size.height * 0.9,
|
Expanded(
|
||||||
child: Align(
|
child: SizedBox(
|
||||||
alignment: FractionalOffset.topCenter,
|
height: MediaQuery.of(context).size.height * 0.9,
|
||||||
child: ListView.builder(
|
child: Align(
|
||||||
reverse: true,
|
alignment: FractionalOffset.topCenter,
|
||||||
itemCount: entries.length,
|
child: ListView.builder(
|
||||||
itemBuilder: (context, index) {
|
reverse: true,
|
||||||
return Column(
|
itemCount: entries.length,
|
||||||
children: [
|
itemBuilder: (context, index) {
|
||||||
Padding(
|
return Column(
|
||||||
padding:
|
children: [
|
||||||
const EdgeInsets.fromLTRB(8.0, 24.0, 8.0, 8.0),
|
Padding(
|
||||||
child: MessageHeader(
|
padding: const EdgeInsets.fromLTRB(
|
||||||
rawTimeStamp: entries[index].key), //date
|
8.0, 24.0, 8.0, 8.0),
|
||||||
),
|
child: MessageHeader(
|
||||||
...entries[index]
|
rawTimeStamp: entries[index].key), //date
|
||||||
.value //messages
|
),
|
||||||
.map((message) {
|
...entries[index]
|
||||||
return MessageWidget(
|
.value //messages
|
||||||
alignment: isReceived(message, context)
|
.asMap()
|
||||||
? Alignment.centerLeft
|
.entries
|
||||||
: Alignment.topRight,
|
.map(
|
||||||
color: isReceived(message, context)
|
(entry) {
|
||||||
? CupertinoColors.systemGrey5
|
final message = entry.value;
|
||||||
: CupertinoColors.systemBlue,
|
final isFinalMessage = 0 == entry.key;
|
||||||
messageColor: isReceived(message, context)
|
final received =
|
||||||
? CupertinoColors.black
|
isReceived(message, context);
|
||||||
: CupertinoColors.white,
|
return (received)
|
||||||
message: message,
|
? MessageWidget(
|
||||||
);
|
alignment: Alignment.topRight,
|
||||||
})
|
margin: const EdgeInsets.fromLTRB(
|
||||||
.toList()
|
8.0, 4.0, 16.0, 4.0),
|
||||||
.reversed,
|
color: const Color(0xFF3CABFA),
|
||||||
],
|
messageColor: CupertinoColors.white,
|
||||||
);
|
message: message,
|
||||||
}),
|
hasTail: isFinalMessage,
|
||||||
)),
|
)
|
||||||
),
|
: MessageWidget(
|
||||||
MessageInput()
|
alignment: Alignment.centerLeft,
|
||||||
],
|
margin: const EdgeInsets.fromLTRB(
|
||||||
|
16.0, 4.0, 8.0, 4.0),
|
||||||
|
color: CupertinoColors.systemGrey5,
|
||||||
|
messageColor: CupertinoColors.black,
|
||||||
|
message: message,
|
||||||
|
hasTail: isFinalMessage,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.toList()
|
||||||
|
.reversed,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
const MessageInput()
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
import 'package:imessage/message_list_view.dart';
|
import 'package:imessage/message_list_view.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart'
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'
|
||||||
show
|
show
|
||||||
LazyLoadScrollView,
|
LazyLoadScrollView,
|
||||||
MessageListController,
|
MessageListController,
|
||||||
@@ -12,6 +13,8 @@ import 'package:imessage/channel_image.dart';
|
|||||||
import 'package:imessage/channel_name_text.dart';
|
import 'package:imessage/channel_name_text.dart';
|
||||||
|
|
||||||
class MessagePage extends StatelessWidget {
|
class MessagePage extends StatelessWidget {
|
||||||
|
const MessagePage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final streamChannel = StreamChannel.of(context);
|
final streamChannel = StreamChannel.of(context);
|
||||||
@@ -22,43 +25,46 @@ class MessagePage extends StatelessWidget {
|
|||||||
middle: Column(
|
middle: Column(
|
||||||
children: [
|
children: [
|
||||||
ChannelImage(
|
ChannelImage(
|
||||||
size: 25,
|
size: 32,
|
||||||
channel: streamChannel.channel,
|
channel: streamChannel.channel,
|
||||||
),
|
),
|
||||||
ChannelNameText(
|
ChannelNameText(
|
||||||
size: 16,
|
|
||||||
channel: streamChannel.channel,
|
channel: streamChannel.channel,
|
||||||
|
size: 10,
|
||||||
|
fontWeight: FontWeight.w300,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
), //ChannelHeader
|
),
|
||||||
child: StreamChatCore(
|
child: StreamChatCore(
|
||||||
client: streamChannel.channel.client,
|
client: streamChannel.channel.client,
|
||||||
child: MessageListCore(
|
child: MessageListCore(
|
||||||
messageListController: messageListController,
|
messageListController: messageListController,
|
||||||
loadingBuilder: (context) {
|
loadingBuilder: (context) {
|
||||||
return Center(
|
return const Center(
|
||||||
child: CupertinoActivityIndicator(),
|
child: CupertinoActivityIndicator(),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
errorBuilder: (context, err) {
|
errorBuilder: (context, err) {
|
||||||
return Center(
|
return const Center(
|
||||||
child: Text('Error'),
|
child: Text('Error'),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
emptyBuilder: (context) {
|
emptyBuilder: (context) {
|
||||||
return Center(
|
return const Center(
|
||||||
child: Text('Nothing here...'),
|
child: Text('Nothing here...'),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
messageListBuilder: (context, messages) => LazyLoadScrollView(
|
messageListBuilder: (context, messages) => LazyLoadScrollView(
|
||||||
onStartOfPage: () async {
|
onStartOfPage: () async {
|
||||||
await messageListController.paginateData!();
|
await messageListController.paginateData!();
|
||||||
},
|
},
|
||||||
child: MessageListView(
|
child: MessageListView(
|
||||||
messages: messages,
|
messages: messages,
|
||||||
),
|
),
|
||||||
))),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,26 @@
|
|||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:imessage/cutom_painter.dart';
|
import 'package:imessage/cutom_painter.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart' show Message;
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'
|
||||||
|
show Message;
|
||||||
|
|
||||||
class MessageWidget extends StatelessWidget {
|
class MessageWidget extends StatelessWidget {
|
||||||
final Alignment alignment;
|
final Alignment alignment;
|
||||||
|
final EdgeInsets margin;
|
||||||
final Message message;
|
final Message message;
|
||||||
final Color color;
|
final Color color;
|
||||||
final Color messageColor;
|
final Color messageColor;
|
||||||
|
final bool hasTail;
|
||||||
|
|
||||||
const MessageWidget(
|
const MessageWidget({
|
||||||
{Key? key,
|
Key? key,
|
||||||
required this.alignment,
|
required this.alignment,
|
||||||
required this.message,
|
required this.margin,
|
||||||
required this.color,
|
required this.message,
|
||||||
required this.messageColor})
|
required this.color,
|
||||||
: super(key: key);
|
required this.messageColor,
|
||||||
|
this.hasTail = false,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@@ -25,10 +30,13 @@ class MessageWidget extends StatelessWidget {
|
|||||||
color: color, message: message, messageColor: messageColor);
|
color: color, message: message, messageColor: messageColor);
|
||||||
} else {
|
} else {
|
||||||
return MessageText(
|
return MessageText(
|
||||||
alignment: alignment,
|
alignment: alignment,
|
||||||
color: color,
|
margin: margin,
|
||||||
message: message,
|
color: color,
|
||||||
messageColor: messageColor);
|
message: message,
|
||||||
|
messageColor: messageColor,
|
||||||
|
hasTail: hasTail,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -102,35 +110,45 @@ class MessageText extends StatelessWidget {
|
|||||||
const MessageText({
|
const MessageText({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.alignment,
|
required this.alignment,
|
||||||
|
required this.margin,
|
||||||
required this.color,
|
required this.color,
|
||||||
required this.message,
|
required this.message,
|
||||||
required this.messageColor,
|
required this.messageColor,
|
||||||
|
required this.hasTail,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
final Alignment alignment;
|
final Alignment alignment;
|
||||||
final Color color;
|
final Color color;
|
||||||
final Message message;
|
final Message message;
|
||||||
final Color messageColor;
|
final Color messageColor;
|
||||||
|
final EdgeInsets margin;
|
||||||
|
final bool hasTail;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
if (message.text?.isEmpty ?? true) {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.only(top: 1),
|
||||||
child: Align(
|
child: Align(
|
||||||
alignment:
|
alignment:
|
||||||
alignment, //Change this to Alignment.topRight or Alignment.topLeft
|
alignment, //Change this to Alignment.topRight or Alignment.topLeft
|
||||||
child: CustomPaint(
|
child: CustomPaint(
|
||||||
painter: ChatBubble(color: color, alignment: alignment),
|
painter:
|
||||||
|
ChatBubble(color: color, alignment: alignment, hasTail: hasTail),
|
||||||
child: Container(
|
child: Container(
|
||||||
margin: const EdgeInsets.fromLTRB(16.0, 8.0, 16.0, 8.0),
|
margin: margin,
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Container(
|
ConstrainedBox(
|
||||||
constraints: BoxConstraints(
|
constraints: BoxConstraints(
|
||||||
maxWidth: MediaQuery.of(context).size.width * 0.65),
|
maxWidth: MediaQuery.of(context).size.width * 0.65,
|
||||||
|
),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(4.0),
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 6.0, vertical: 4),
|
||||||
child: Text(
|
child: Text(
|
||||||
message.text!,
|
message.text!,
|
||||||
style: TextStyle(color: messageColor),
|
style: TextStyle(color: messageColor),
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import 'package:intl/intl.dart';
|
|||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
|
||||||
String formatDate(DateTime date) {
|
String formatDate(DateTime date) {
|
||||||
final dateFormat = DateFormat.yMd().add_jm();
|
final dateFormat = DateFormat.yMd();
|
||||||
return dateFormat.format(date);
|
return dateFormat.format(date);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -12,7 +12,7 @@ String formatDateSameWeek(DateTime date) {
|
|||||||
if (date.day == DateTime.now().day) {
|
if (date.day == DateTime.now().day) {
|
||||||
dateFormat = DateFormat('hh:mm a');
|
dateFormat = DateFormat('hh:mm a');
|
||||||
} else {
|
} else {
|
||||||
dateFormat = DateFormat('EEEE, hh:mm a');
|
dateFormat = DateFormat('EEEE');
|
||||||
}
|
}
|
||||||
return dateFormat.format(date);
|
return dateFormat.format(date);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,20 +24,20 @@ dependencies:
|
|||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
intl: ^0.17.0
|
intl: ^0.17.0
|
||||||
stream_chat_flutter: ^3.0.0
|
stream_chat_flutter_core: ^3.0.0
|
||||||
animations: ^2.0.1
|
animations: ^2.0.1
|
||||||
collection: ^1.15.0
|
collection: ^1.15.0
|
||||||
cached_network_image: ^3.1.0
|
cached_network_image: ^3.1.0
|
||||||
|
|
||||||
|
|
||||||
# The following adds the Cupertino Icons font to your application.
|
# The following adds the Cupertino Icons font to your application.
|
||||||
# Use with the CupertinoIcons class for iOS style icons.
|
# Use with the CupertinoIcons class for iOS style icons.
|
||||||
cupertino_icons: ^1.0.3
|
cupertino_icons: ^1.0.3
|
||||||
|
image_picker: ^0.8.4+4
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
pedantic: ^1.11.1
|
flutter_lints: ^1.0.0
|
||||||
|
|
||||||
# For information on the generic Dart part of this file, see the
|
# For information on the generic Dart part of this file, see the
|
||||||
# following page: https://dart.dev/tools/pub/pubspec
|
# following page: https://dart.dev/tools/pub/pubspec
|
||||||
|
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
// This is a basic Flutter widget test.
|
|
||||||
//
|
|
||||||
// To perform an interaction with a widget in your test, use the WidgetTester
|
|
||||||
// utility that Flutter provides. For example, you can send tap and scroll
|
|
||||||
// gestures. You can also use WidgetTester to find child widgets in the widget
|
|
||||||
// tree, read text, and verify that the values of widget properties are correct.
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
|
||||||
|
|
||||||
import 'package:imessage/main.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
|
|
||||||
// Build our app and trigger a frame.
|
|
||||||
await tester.pumpWidget(IMessage());
|
|
||||||
|
|
||||||
// Verify that our counter starts at 0.
|
|
||||||
expect(find.text('0'), findsOneWidget);
|
|
||||||
expect(find.text('1'), findsNothing);
|
|
||||||
|
|
||||||
// Tap the '+' icon and trigger a frame.
|
|
||||||
await tester.tap(find.byIcon(Icons.add));
|
|
||||||
await tester.pump();
|
|
||||||
|
|
||||||
// Verify that our counter has incremented.
|
|
||||||
expect(find.text('0'), findsNothing);
|
|
||||||
expect(find.text('1'), findsOneWidget);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user