added lint changes, started migrating
This commit is contained in:
@@ -13,52 +13,138 @@ linter:
|
||||
# these rules are documented on and in the same order as
|
||||
# the Dart Lint rules page to make maintenance easier
|
||||
# https://github.com/dart-lang/linter/blob/master/example/all.yaml
|
||||
# - always_declare_return_types
|
||||
# - always_specify_types
|
||||
# - annotate_overrides
|
||||
# - avoid_as
|
||||
- always_use_package_imports
|
||||
- avoid_empty_else
|
||||
- avoid_init_to_null
|
||||
- avoid_return_types_on_setters
|
||||
- avoid_web_libraries_in_flutter
|
||||
- await_only_futures
|
||||
- camel_case_types
|
||||
- avoid_relative_lib_imports
|
||||
- avoid_slow_async_io
|
||||
- avoid_types_as_parameter_names
|
||||
- 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_api_docs
|
||||
- package_names
|
||||
- package_prefixed_library_names
|
||||
- prefer_is_not_empty
|
||||
# - prefer_mixin # https://github.com/dart-lang/language/issues/32
|
||||
# - public_member_api_docs
|
||||
- slash_for_doc_comments
|
||||
# - sort_constructors_first
|
||||
# - sort_unnamed_constructors_first
|
||||
# - super_goes_last # no longer needed w/ Dart 2
|
||||
- invariant_booleans
|
||||
- iterable_contains_unrelated_type
|
||||
- list_remove_unrelated_type
|
||||
- literal_only_boolean_expressions
|
||||
- no_adjacent_strings_in_list
|
||||
- no_duplicate_case_values
|
||||
- no_logic_in_create_state
|
||||
- prefer_void_to_null
|
||||
- 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
|
||||
- omit_local_variable_types
|
||||
- use_key_in_widget_constructors
|
||||
- valid_regexps
|
||||
- always_declare_return_types
|
||||
- always_require_non_null_named_parameters
|
||||
- annotate_overrides
|
||||
- avoid_bool_literals_in_conditional_expressions
|
||||
- avoid_catching_errors
|
||||
- avoid_init_to_null
|
||||
- avoid_null_checks_in_equality_operators
|
||||
- avoid_positional_boolean_parameters
|
||||
- avoid_private_typedef_functions
|
||||
- avoid_redundant_argument_values
|
||||
- avoid_return_types_on_setters
|
||||
- avoid_returning_null_for_void
|
||||
- avoid_shadowing_type_parameters
|
||||
- avoid_single_cascade_in_expression_statements
|
||||
- avoid_unnecessary_containers
|
||||
- avoid_unused_constructor_parameters
|
||||
- await_only_futures
|
||||
- camel_case_extensions
|
||||
- camel_case_types
|
||||
- cascade_invocations
|
||||
|
||||
- constant_identifier_names
|
||||
- curly_braces_in_flow_control_structures
|
||||
- directives_ordering
|
||||
- empty_catches
|
||||
- empty_constructor_bodies
|
||||
- exhaustive_cases
|
||||
- file_names
|
||||
- implementation_imports
|
||||
- join_return_with_assignment
|
||||
- leading_newlines_in_multiline_strings
|
||||
- library_names
|
||||
- library_prefixes
|
||||
- lines_longer_than_80_chars
|
||||
- missing_whitespace_between_adjacent_strings
|
||||
- non_constant_identifier_names
|
||||
- null_closures
|
||||
- one_member_abstracts
|
||||
- only_throw_errors
|
||||
- package_api_docs
|
||||
- package_prefixed_library_names
|
||||
- parameter_assignments
|
||||
- prefer_adjacent_string_concatenation
|
||||
- prefer_asserts_in_initializer_lists
|
||||
- prefer_asserts_with_message
|
||||
- prefer_collection_literals
|
||||
- prefer_conditional_assignment
|
||||
- prefer_const_constructors
|
||||
- prefer_const_constructors_in_immutables
|
||||
- prefer_const_declarations
|
||||
- prefer_const_literals_to_create_immutables
|
||||
- prefer_constructors_over_static_methods
|
||||
- prefer_contains
|
||||
- prefer_equal_for_default_values
|
||||
- prefer_expression_function_bodies
|
||||
- prefer_final_fields
|
||||
- prefer_final_in_for_each
|
||||
- prefer_final_locals
|
||||
- prefer_function_declarations_over_variables
|
||||
- prefer_generic_function_type_aliases
|
||||
- prefer_if_elements_to_conditional_expressions
|
||||
- prefer_if_null_operators
|
||||
- prefer_initializing_formals
|
||||
- prefer_inlined_adds
|
||||
- prefer_int_literals
|
||||
- prefer_interpolation_to_compose_strings
|
||||
- prefer_is_empty
|
||||
- prefer_is_not_empty
|
||||
- prefer_is_not_operator
|
||||
- prefer_null_aware_operators
|
||||
- prefer_single_quotes
|
||||
- prefer_spread_collections
|
||||
- prefer_typing_uninitialized_variables
|
||||
- provide_deprecation_message
|
||||
- public_member_api_docs
|
||||
- recursive_getters
|
||||
- sized_box_for_whitespace
|
||||
- slash_for_doc_comments
|
||||
- sort_child_properties_last
|
||||
- sort_constructors_first
|
||||
- sort_unnamed_constructors_first
|
||||
|
||||
- type_annotate_public_apis
|
||||
- type_init_formals
|
||||
- unnecessary_await_in_return
|
||||
- unnecessary_brace_in_string_interps
|
||||
- unnecessary_const
|
||||
- unnecessary_getters_setters
|
||||
- unnecessary_lambdas
|
||||
- unnecessary_new
|
||||
- unnecessary_null_aware_assignments
|
||||
- unnecessary_null_in_if_null_operators
|
||||
- unnecessary_nullable_for_final_variable_declarations
|
||||
- unnecessary_parenthesis
|
||||
- unnecessary_raw_strings
|
||||
- unnecessary_string_escapes
|
||||
- unnecessary_string_interpolations
|
||||
- unnecessary_this
|
||||
- use_is_even_rather_than_modulo
|
||||
- use_late_for_private_fields_and_variables
|
||||
- use_rethrow_when_possible
|
||||
- use_setters_to_change_properties
|
||||
- use_to_and_as_if_applicable
|
||||
- package_names
|
||||
- sort_pub_dependencies
|
||||
|
||||
- cast_nullable_to_non_nullable
|
||||
- unnecessary_null_checks
|
||||
- tighten_type_of_initializing_formals
|
||||
- null_check_on_nullable_type_parameter
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export 'attachment_upload_state_builder.dart';
|
||||
export 'attachment_widget.dart'
|
||||
show AttachmentError, AttachmentSource, AttachmentSourceX;
|
||||
export 'file_attachment.dart';
|
||||
export 'giphy_attachment.dart';
|
||||
export 'image_attachment.dart';
|
||||
export 'video_attachment.dart';
|
||||
export 'attachment_upload_state_builder.dart';
|
||||
export 'attachment_widget.dart'
|
||||
show AttachmentError, AttachmentSource, AttachmentSourceX;
|
||||
|
||||
@@ -1,57 +1,59 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||
|
||||
import '../stream_chat_theme.dart';
|
||||
import '../utils.dart';
|
||||
|
||||
/// Title for attachments
|
||||
class AttachmentTitle extends StatelessWidget {
|
||||
/// Supply attachment and theme for constructing title
|
||||
const AttachmentTitle({
|
||||
Key? key,
|
||||
required this.attachment,
|
||||
required this.messageTheme,
|
||||
}) : super(key: key);
|
||||
|
||||
/// Theme to apply to text
|
||||
final MessageTheme messageTheme;
|
||||
|
||||
/// Attachment data to display
|
||||
final Attachment attachment;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
if (attachment.titleLink != null) {
|
||||
launchURL(context, attachment.titleLink!);
|
||||
}
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: <Widget>[
|
||||
if (attachment.title != null)
|
||||
Text(
|
||||
attachment.title!,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: messageTheme.messageText?.copyWith(
|
||||
color: StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||
fontWeight: FontWeight.bold,
|
||||
Widget build(BuildContext context) => GestureDetector(
|
||||
onTap: () {
|
||||
if (attachment.titleLink != null) {
|
||||
launchURL(context, attachment.titleLink);
|
||||
}
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: <Widget>[
|
||||
if (attachment.title != null)
|
||||
Text(
|
||||
attachment.title!,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: messageTheme.messageText?.copyWith(
|
||||
color: StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (attachment.titleLink != null || attachment.ogScrapeUrl != null)
|
||||
Text(
|
||||
Uri.parse(attachment.titleLink ?? attachment.ogScrapeUrl!)
|
||||
.authority
|
||||
.split('.')
|
||||
.reversed
|
||||
.take(2)
|
||||
.toList()
|
||||
.reversed
|
||||
.join('.'),
|
||||
style: messageTheme.messageText,
|
||||
),
|
||||
],
|
||||
if (attachment.titleLink != null ||
|
||||
attachment.ogScrapeUrl != null)
|
||||
Text(
|
||||
Uri.parse(attachment.titleLink ?? attachment.ogScrapeUrl!)
|
||||
.authority
|
||||
.split('.')
|
||||
.reversed
|
||||
.take(2)
|
||||
.toList()
|
||||
.reversed
|
||||
.join('.'),
|
||||
style: messageTheme.messageText,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
+5
-2
@@ -2,9 +2,13 @@ import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat_flutter/src/upload_progress_indicator.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
|
||||
/// Widget to build in progress
|
||||
typedef InProgressBuilder = Widget Function(BuildContext, int, int);
|
||||
|
||||
/// Widget to build on failure
|
||||
typedef FailedBuilder = Widget Function(BuildContext, String);
|
||||
|
||||
/// Widget to display attachment upload state
|
||||
class AttachmentUploadStateBuilder extends StatelessWidget {
|
||||
final Message message;
|
||||
final Attachment attachment;
|
||||
@@ -87,7 +91,6 @@ class _IconButton extends StatelessWidget {
|
||||
elevation: 0,
|
||||
highlightElevation: 0,
|
||||
focusElevation: 0,
|
||||
disabledElevation: 0,
|
||||
hoverElevation: 0,
|
||||
onPressed: onPressed,
|
||||
fillColor:
|
||||
@@ -237,7 +240,7 @@ class _SuccessState extends StatelessWidget {
|
||||
alignment: Alignment.topRight,
|
||||
child: CircleAvatar(
|
||||
backgroundColor: StreamChatTheme.of(context).colorTheme.overlayDark,
|
||||
maxRadius: 12.0,
|
||||
maxRadius: 12,
|
||||
child: StreamSvgIcon.check(
|
||||
color: StreamChatTheme.of(context).colorTheme.white,
|
||||
),
|
||||
|
||||
@@ -42,7 +42,7 @@ class FileAttachment extends AttachmentWidget {
|
||||
onTap: onAttachmentTap,
|
||||
child: Container(
|
||||
width: size?.width ?? 100,
|
||||
height: 56.0,
|
||||
height: 56,
|
||||
decoration: BoxDecoration(
|
||||
color: colorTheme.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
@@ -54,12 +54,12 @@ class FileAttachment extends AttachmentWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
height: 40.0,
|
||||
height: 40,
|
||||
width: 33.33,
|
||||
margin: EdgeInsets.all(8.0),
|
||||
margin: EdgeInsets.all(8),
|
||||
child: _getFileTypeImage(context),
|
||||
),
|
||||
SizedBox(width: 8.0),
|
||||
SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
@@ -71,12 +71,12 @@ class FileAttachment extends AttachmentWidget {
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
SizedBox(height: 3.0),
|
||||
SizedBox(height: 3),
|
||||
_buildSubtitle(context),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8.0),
|
||||
SizedBox(width: 8),
|
||||
_buildTrailing(context),
|
||||
],
|
||||
),
|
||||
@@ -87,7 +87,7 @@ class FileAttachment extends AttachmentWidget {
|
||||
|
||||
ShapeBorder _getDefaultShape(BuildContext context) {
|
||||
return RoundedRectangleBorder(
|
||||
side: BorderSide(width: 0.0, color: Colors.transparent),
|
||||
side: BorderSide(width: 0, color: Colors.transparent),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
);
|
||||
}
|
||||
@@ -159,8 +159,8 @@ class FileAttachment extends AttachmentWidget {
|
||||
placeholderBuilder: (_) {
|
||||
return Center(
|
||||
child: Container(
|
||||
width: 20.0,
|
||||
height: 20.0,
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: const CircularProgressIndicator(),
|
||||
),
|
||||
);
|
||||
@@ -171,8 +171,8 @@ class FileAttachment extends AttachmentWidget {
|
||||
placeholderBuilder: (_) {
|
||||
return Center(
|
||||
child: Container(
|
||||
width: 20.0,
|
||||
height: 20.0,
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: const CircularProgressIndicator(),
|
||||
),
|
||||
);
|
||||
@@ -197,7 +197,6 @@ class FileAttachment extends AttachmentWidget {
|
||||
elevation: 0,
|
||||
highlightElevation: 0,
|
||||
focusElevation: 0,
|
||||
disabledElevation: 0,
|
||||
hoverElevation: 0,
|
||||
onPressed: onPressed,
|
||||
fillColor: fillColor,
|
||||
@@ -214,7 +213,7 @@ class FileAttachment extends AttachmentWidget {
|
||||
var trailingWidget = trailing;
|
||||
trailingWidget ??= attachment.uploadState.when(
|
||||
preparing: () => Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: _buildButton(
|
||||
icon: StreamSvgIcon.close(color: theme.colorTheme.white),
|
||||
fillColor: theme.colorTheme.overlayDark,
|
||||
@@ -222,7 +221,7 @@ class FileAttachment extends AttachmentWidget {
|
||||
),
|
||||
),
|
||||
inProgress: (_, __) => Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: _buildButton(
|
||||
icon: StreamSvgIcon.close(color: theme.colorTheme.white),
|
||||
fillColor: theme.colorTheme.overlayDark,
|
||||
@@ -230,15 +229,15 @@ class FileAttachment extends AttachmentWidget {
|
||||
),
|
||||
),
|
||||
success: () => Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: CircleAvatar(
|
||||
backgroundColor: theme.colorTheme.accentBlue,
|
||||
maxRadius: 12.0,
|
||||
maxRadius: 12,
|
||||
child: StreamSvgIcon.check(color: theme.colorTheme.white),
|
||||
),
|
||||
),
|
||||
failed: (_) => Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: _buildButton(
|
||||
icon: StreamSvgIcon.retry(color: theme.colorTheme.white),
|
||||
fillColor: theme.colorTheme.overlayDark,
|
||||
@@ -251,7 +250,6 @@ class FileAttachment extends AttachmentWidget {
|
||||
) ??
|
||||
IconButton(
|
||||
icon: StreamSvgIcon.cloudDownload(color: theme.colorTheme.black),
|
||||
padding: const EdgeInsets.all(8),
|
||||
visualDensity: VisualDensity.compact,
|
||||
splashRadius: 16,
|
||||
onPressed: () {
|
||||
@@ -262,7 +260,6 @@ class FileAttachment extends AttachmentWidget {
|
||||
if (message.status == MessageSendingStatus.sent) {
|
||||
trailingWidget = IconButton(
|
||||
icon: StreamSvgIcon.cloudDownload(color: theme.colorTheme.black),
|
||||
padding: const EdgeInsets.all(8),
|
||||
visualDensity: VisualDensity.compact,
|
||||
splashRadius: 16,
|
||||
onPressed: () {
|
||||
@@ -304,9 +301,9 @@ class FileAttachment extends AttachmentWidget {
|
||||
progressIndicatorColor: theme.colorTheme.accentBlue,
|
||||
);
|
||||
},
|
||||
success: () => Text('${fileSize(size, 2)}', style: textStyle),
|
||||
success: () => Text(fileSize(size), style: textStyle),
|
||||
failed: (_) => Text('UPLOAD ERROR', style: textStyle),
|
||||
) ??
|
||||
Text('${fileSize(size)}', style: textStyle);
|
||||
Text(fileSize(size), style: textStyle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,10 +52,10 @@ class GiphyAttachment extends AttachmentWidget {
|
||||
clipBehavior: Clip.antiAlias,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.only(
|
||||
topRight: Radius.circular(16.0),
|
||||
bottomRight: Radius.circular(0.0),
|
||||
topLeft: Radius.circular(16.0),
|
||||
bottomLeft: Radius.circular(16.0),
|
||||
topRight: Radius.circular(16),
|
||||
bottomRight: Radius.circular(0),
|
||||
topLeft: Radius.circular(16),
|
||||
bottomLeft: Radius.circular(16),
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
@@ -63,7 +63,7 @@ class GiphyAttachment extends AttachmentWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: Row(
|
||||
children: [
|
||||
StreamSvgIcon.giphyIcon(),
|
||||
@@ -91,7 +91,7 @@ class GiphyAttachment extends AttachmentWidget {
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(2.0),
|
||||
padding: const EdgeInsets.all(2),
|
||||
child: GestureDetector(
|
||||
onTap: () => onAttachmentTap ?? _onImageTap(context),
|
||||
child: CachedNetworkImage(
|
||||
@@ -123,8 +123,6 @@ class GiphyAttachment extends AttachmentWidget {
|
||||
height: 0.5,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
@@ -156,7 +154,7 @@ class GiphyAttachment extends AttachmentWidget {
|
||||
.colorTheme
|
||||
.black
|
||||
.withOpacity(0.2),
|
||||
height: 50.0,
|
||||
height: 50,
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
@@ -189,7 +187,7 @@ class GiphyAttachment extends AttachmentWidget {
|
||||
.colorTheme
|
||||
.black
|
||||
.withOpacity(0.2),
|
||||
height: 50.0,
|
||||
height: 50,
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
@@ -217,11 +215,11 @@ class GiphyAttachment extends AttachmentWidget {
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 4.0),
|
||||
SizedBox(height: 4),
|
||||
Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
@@ -230,10 +228,10 @@ class GiphyAttachment extends AttachmentWidget {
|
||||
.colorTheme
|
||||
.black
|
||||
.withOpacity(0.5),
|
||||
size: 16.0,
|
||||
size: 16,
|
||||
),
|
||||
SizedBox(
|
||||
width: 8.0,
|
||||
width: 8,
|
||||
),
|
||||
Text(
|
||||
'Only visible to you',
|
||||
@@ -332,8 +330,8 @@ class GiphyAttachment extends AttachmentWidget {
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8.0,
|
||||
vertical: 4.0,
|
||||
horizontal: 8,
|
||||
vertical: 4,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
|
||||
@@ -34,137 +34,131 @@ class ImageAttachment extends AttachmentWidget {
|
||||
);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return source.when(
|
||||
local: () {
|
||||
if (attachment.localUri == null || attachment.file?.bytes == null) {
|
||||
return AttachmentError(size: size);
|
||||
}
|
||||
return _buildImageAttachment(
|
||||
context,
|
||||
Image.memory(
|
||||
attachment.file!.bytes!,
|
||||
height: size?.height,
|
||||
width: size?.width,
|
||||
fit: BoxFit.cover,
|
||||
errorBuilder: (context, _, __) {
|
||||
return Image.asset(
|
||||
Widget build(BuildContext context) => source.when(
|
||||
local: () {
|
||||
if (attachment.localUri == null || attachment.file?.bytes == null) {
|
||||
return AttachmentError(size: size);
|
||||
}
|
||||
return _buildImageAttachment(
|
||||
context,
|
||||
Image.memory(
|
||||
attachment.file!.bytes!,
|
||||
height: size?.height,
|
||||
width: size?.width,
|
||||
fit: BoxFit.cover,
|
||||
errorBuilder: (context, _, __) => Image.asset(
|
||||
'images/placeholder.png',
|
||||
package: 'stream_chat_flutter',
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
network: () {
|
||||
var imageUrl =
|
||||
attachment.thumbUrl ?? attachment.imageUrl ?? attachment.assetUrl;
|
||||
|
||||
if (imageUrl == null) {
|
||||
return AttachmentError(size: size);
|
||||
}
|
||||
|
||||
var imageUri = Uri.parse(imageUrl);
|
||||
if (imageUri.host == 'stream-io-cdn.com') {
|
||||
imageUri = imageUri.replace(queryParameters: {
|
||||
...imageUri.queryParameters,
|
||||
'h': '500',
|
||||
'w': '500',
|
||||
'crop': 'center',
|
||||
'resize': 'crop',
|
||||
});
|
||||
} else if (imageUri.host == 'stream-cloud-uploads.imgix.net') {
|
||||
imageUri = imageUri.replace(queryParameters: {
|
||||
...imageUri.queryParameters,
|
||||
'height': '500',
|
||||
'width': '500',
|
||||
'fit': 'crop',
|
||||
});
|
||||
}
|
||||
imageUrl = imageUri.toString();
|
||||
|
||||
return _buildImageAttachment(
|
||||
context,
|
||||
CachedNetworkImage(
|
||||
cacheKey: imageUri.path,
|
||||
height: size?.height,
|
||||
width: size?.width,
|
||||
placeholder: (_, __) {
|
||||
final image = Image.asset(
|
||||
'images/placeholder.png',
|
||||
fit: BoxFit.cover,
|
||||
package: 'stream_chat_flutter',
|
||||
);
|
||||
final colorTheme = StreamChatTheme.of(context).colorTheme;
|
||||
return Shimmer.fromColors(
|
||||
baseColor: colorTheme.greyGainsboro,
|
||||
highlightColor: colorTheme.whiteSmoke,
|
||||
child: image,
|
||||
);
|
||||
},
|
||||
imageUrl: imageUrl,
|
||||
errorWidget: (context, url, error) {
|
||||
return AttachmentError(size: size);
|
||||
},
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildImageAttachment(BuildContext context, Widget imageWidget) {
|
||||
return ConstrainedBox(
|
||||
constraints: BoxConstraints.loose(size!),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Stack(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: onAttachmentTap ??
|
||||
() async {
|
||||
final result = await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (_) {
|
||||
final channel = StreamChannel.of(context).channel;
|
||||
return StreamChannel(
|
||||
channel: channel,
|
||||
child: FullScreenMedia(
|
||||
mediaAttachments: [attachment],
|
||||
userName: message.user?.name,
|
||||
message: message,
|
||||
onShowMessage: onShowMessage,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
if (result != null) onReturnAction?.call(result);
|
||||
},
|
||||
child: imageWidget,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: AttachmentUploadStateBuilder(
|
||||
message: message,
|
||||
attachment: attachment,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (showTitle && attachment.title != null)
|
||||
Material(
|
||||
color: messageTheme.messageBackgroundColor,
|
||||
child: AttachmentTitle(
|
||||
messageTheme: messageTheme,
|
||||
attachment: attachment,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
);
|
||||
},
|
||||
network: () {
|
||||
var imageUrl =
|
||||
attachment.thumbUrl ?? attachment.imageUrl ?? attachment.assetUrl;
|
||||
|
||||
if (imageUrl == null) {
|
||||
return AttachmentError(size: size);
|
||||
}
|
||||
|
||||
var imageUri = Uri.parse(imageUrl);
|
||||
if (imageUri.host == 'stream-io-cdn.com') {
|
||||
imageUri = imageUri.replace(queryParameters: {
|
||||
...imageUri.queryParameters,
|
||||
'h': '500',
|
||||
'w': '500',
|
||||
'crop': 'center',
|
||||
'resize': 'crop',
|
||||
});
|
||||
} else if (imageUri.host == 'stream-cloud-uploads.imgix.net') {
|
||||
imageUri = imageUri.replace(queryParameters: {
|
||||
...imageUri.queryParameters,
|
||||
'height': '500',
|
||||
'width': '500',
|
||||
'fit': 'crop',
|
||||
});
|
||||
}
|
||||
imageUrl = imageUri.toString();
|
||||
|
||||
return _buildImageAttachment(
|
||||
context,
|
||||
CachedNetworkImage(
|
||||
cacheKey: imageUri.path,
|
||||
height: size?.height,
|
||||
width: size?.width,
|
||||
placeholder: (_, __) {
|
||||
final image = Image.asset(
|
||||
'images/placeholder.png',
|
||||
fit: BoxFit.cover,
|
||||
package: 'stream_chat_flutter',
|
||||
);
|
||||
final colorTheme = StreamChatTheme.of(context).colorTheme;
|
||||
return Shimmer.fromColors(
|
||||
baseColor: colorTheme.greyGainsboro,
|
||||
highlightColor: colorTheme.whiteSmoke,
|
||||
child: image,
|
||||
);
|
||||
},
|
||||
imageUrl: imageUrl,
|
||||
errorWidget: (context, url, error) => AttachmentError(size: size),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
Widget _buildImageAttachment(BuildContext context, Widget imageWidget) =>
|
||||
ConstrainedBox(
|
||||
constraints: BoxConstraints.loose(size!),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Stack(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: onAttachmentTap ??
|
||||
() async {
|
||||
final result = await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (_) {
|
||||
final channel =
|
||||
StreamChannel.of(context).channel;
|
||||
return StreamChannel(
|
||||
channel: channel,
|
||||
child: FullScreenMedia(
|
||||
mediaAttachments: [attachment],
|
||||
userName: message.user?.name,
|
||||
message: message,
|
||||
onShowMessage: onShowMessage,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
if (result != null) onReturnAction?.call(result);
|
||||
},
|
||||
child: imageWidget,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: AttachmentUploadStateBuilder(
|
||||
message: message,
|
||||
attachment: attachment,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (showTitle && attachment.title != null)
|
||||
Material(
|
||||
color: messageTheme.messageBackgroundColor,
|
||||
child: AttachmentTitle(
|
||||
messageTheme: messageTheme,
|
||||
attachment: attachment,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -30,100 +30,97 @@ class VideoAttachment extends AttachmentWidget {
|
||||
);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return source.when(
|
||||
local: () {
|
||||
if (attachment.file == null) {
|
||||
return AttachmentError(size: size);
|
||||
}
|
||||
return _buildVideoAttachment(
|
||||
context,
|
||||
VideoThumbnailImage(
|
||||
video: attachment.file!.path!,
|
||||
height: size?.height,
|
||||
width: size?.width,
|
||||
fit: BoxFit.cover,
|
||||
errorBuilder: (_, __) => AttachmentError(size: size),
|
||||
),
|
||||
);
|
||||
},
|
||||
network: () {
|
||||
if (attachment.assetUrl == null) {
|
||||
return AttachmentError(size: size);
|
||||
}
|
||||
return _buildVideoAttachment(
|
||||
context,
|
||||
VideoThumbnailImage(
|
||||
video: attachment.assetUrl!,
|
||||
height: size?.height,
|
||||
width: size?.width,
|
||||
fit: BoxFit.cover,
|
||||
errorBuilder: (_, __) => AttachmentError(size: size),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
Widget build(BuildContext context) => source.when(
|
||||
local: () {
|
||||
if (attachment.file == null) {
|
||||
return AttachmentError(size: size);
|
||||
}
|
||||
return _buildVideoAttachment(
|
||||
context,
|
||||
VideoThumbnailImage(
|
||||
video: attachment.file!.path!,
|
||||
height: size?.height,
|
||||
width: size?.width,
|
||||
fit: BoxFit.cover,
|
||||
errorBuilder: (_, __) => AttachmentError(size: size),
|
||||
),
|
||||
);
|
||||
},
|
||||
network: () {
|
||||
if (attachment.assetUrl == null) {
|
||||
return AttachmentError(size: size);
|
||||
}
|
||||
return _buildVideoAttachment(
|
||||
context,
|
||||
VideoThumbnailImage(
|
||||
video: attachment.assetUrl!,
|
||||
height: size?.height,
|
||||
width: size?.width,
|
||||
fit: BoxFit.cover,
|
||||
errorBuilder: (_, __) => AttachmentError(size: size),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
Widget _buildVideoAttachment(BuildContext context, Widget videoWidget) {
|
||||
return ConstrainedBox(
|
||||
constraints: BoxConstraints.loose(size ?? Size.infinite),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: GestureDetector(
|
||||
onTap: onAttachmentTap ??
|
||||
() async {
|
||||
final channel = StreamChannel.of(context).channel;
|
||||
final res = await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (_) => StreamChannel(
|
||||
channel: channel,
|
||||
child: FullScreenMedia(
|
||||
mediaAttachments: [attachment],
|
||||
userName: message.user?.name,
|
||||
message: message,
|
||||
onShowMessage: onShowMessage,
|
||||
Widget _buildVideoAttachment(BuildContext context, Widget videoWidget) =>
|
||||
ConstrainedBox(
|
||||
constraints: BoxConstraints.loose(size ?? Size.infinite),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: GestureDetector(
|
||||
onTap: onAttachmentTap ??
|
||||
() async {
|
||||
final channel = StreamChannel.of(context).channel;
|
||||
final res = await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (_) => StreamChannel(
|
||||
channel: channel,
|
||||
child: FullScreenMedia(
|
||||
mediaAttachments: [attachment],
|
||||
userName: message.user?.name,
|
||||
message: message,
|
||||
onShowMessage: onShowMessage,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
if (res != null) onReturnAction?.call(res);
|
||||
},
|
||||
child: Stack(
|
||||
children: [
|
||||
videoWidget,
|
||||
Center(
|
||||
child: Material(
|
||||
shape: CircleBorder(),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Icon(Icons.play_arrow),
|
||||
);
|
||||
if (res != null) onReturnAction?.call(res);
|
||||
},
|
||||
child: Stack(
|
||||
children: [
|
||||
videoWidget,
|
||||
const Center(
|
||||
child: Material(
|
||||
shape: CircleBorder(),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(16),
|
||||
child: Icon(Icons.play_arrow),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: AttachmentUploadStateBuilder(
|
||||
message: message,
|
||||
attachment: attachment,
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: AttachmentUploadStateBuilder(
|
||||
message: message,
|
||||
attachment: attachment,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (attachment.title != null)
|
||||
Material(
|
||||
color: messageTheme.messageBackgroundColor,
|
||||
child: AttachmentTitle(
|
||||
messageTheme: messageTheme,
|
||||
attachment: attachment,
|
||||
if (attachment.title != null)
|
||||
Material(
|
||||
color: messageTheme.messageBackgroundColor,
|
||||
child: AttachmentTitle(
|
||||
messageTheme: messageTheme,
|
||||
attachment: attachment,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -42,27 +42,25 @@ class AttachmentActionsModal extends StatelessWidget {
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () => Navigator.maybePop(context),
|
||||
child: _buildPage(context),
|
||||
);
|
||||
}
|
||||
Widget build(BuildContext context) => GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () => Navigator.maybePop(context),
|
||||
child: _buildPage(context),
|
||||
);
|
||||
|
||||
Widget _buildPage(context) {
|
||||
final theme = StreamChatTheme.of(context);
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
SizedBox(height: kToolbarHeight),
|
||||
const SizedBox(height: kToolbarHeight),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8.0),
|
||||
padding: const EdgeInsets.only(right: 8),
|
||||
child: Container(
|
||||
width: MediaQuery.of(context).size.width * 0.5,
|
||||
clipBehavior: Clip.hardEdge,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(16.0),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Container(
|
||||
child: Column(
|
||||
@@ -73,7 +71,7 @@ class AttachmentActionsModal extends StatelessWidget {
|
||||
context,
|
||||
'Reply',
|
||||
StreamSvgIcon.iconCurveLineLeftUp(
|
||||
size: 24.0,
|
||||
size: 24,
|
||||
color: theme.colorTheme.grey,
|
||||
),
|
||||
() {
|
||||
@@ -84,7 +82,7 @@ class AttachmentActionsModal extends StatelessWidget {
|
||||
context,
|
||||
'Show in Chat',
|
||||
StreamSvgIcon.eye(
|
||||
size: 24.0,
|
||||
size: 24,
|
||||
color: theme.colorTheme.black,
|
||||
),
|
||||
onShowMessage,
|
||||
@@ -93,7 +91,7 @@ class AttachmentActionsModal extends StatelessWidget {
|
||||
context,
|
||||
'Save ${message.attachments[currentIndex].type == 'video' ? 'Video' : 'Image'}',
|
||||
StreamSvgIcon.iconSave(
|
||||
size: 24.0,
|
||||
size: 24,
|
||||
color: theme.colorTheme.grey,
|
||||
),
|
||||
() {
|
||||
@@ -144,7 +142,7 @@ class AttachmentActionsModal extends StatelessWidget {
|
||||
context,
|
||||
'Delete',
|
||||
StreamSvgIcon.delete(
|
||||
size: 24.0,
|
||||
size: 24,
|
||||
color: theme.colorTheme.accentRed,
|
||||
),
|
||||
() {
|
||||
@@ -201,7 +199,7 @@ class AttachmentActionsModal extends StatelessWidget {
|
||||
child: InkWell(
|
||||
onTap: onTap,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
|
||||
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
|
||||
child: Row(
|
||||
children: [
|
||||
icon,
|
||||
@@ -271,7 +269,7 @@ class AttachmentActionsModal extends StatelessWidget {
|
||||
children: [
|
||||
CircularProgressIndicator(
|
||||
value: progress.toProgressIndicatorValue,
|
||||
strokeWidth: 8.0,
|
||||
strokeWidth: 8,
|
||||
valueColor: AlwaysStoppedAnimation(
|
||||
theme.colorTheme.accentBlue,
|
||||
),
|
||||
|
||||
@@ -30,7 +30,6 @@ class StreamBackButton extends StatelessWidget {
|
||||
elevation: 0,
|
||||
highlightElevation: 0,
|
||||
focusElevation: 0,
|
||||
disabledElevation: 0,
|
||||
hoverElevation: 0,
|
||||
onPressed: () {
|
||||
if (onPressed != null) {
|
||||
@@ -39,7 +38,7 @@ class StreamBackButton extends StatelessWidget {
|
||||
Navigator.maybePop(context);
|
||||
}
|
||||
},
|
||||
padding: const EdgeInsets.all(14.0),
|
||||
padding: const EdgeInsets.all(14),
|
||||
child: StreamSvgIcon.left(
|
||||
size: 24,
|
||||
color: StreamChatTheme.of(context).colorTheme.black,
|
||||
|
||||
@@ -7,7 +7,7 @@ import 'option_list_tile.dart';
|
||||
class ChannelBottomSheet extends StatefulWidget {
|
||||
final VoidCallback? onViewInfoTap;
|
||||
|
||||
ChannelBottomSheet({this.onViewInfoTap});
|
||||
const ChannelBottomSheet({this.onViewInfoTap});
|
||||
|
||||
@override
|
||||
_ChannelBottomSheetState createState() => _ChannelBottomSheetState();
|
||||
@@ -31,29 +31,29 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
|
||||
clipBehavior: Clip.antiAlias,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(16.0),
|
||||
topRight: Radius.circular(16.0),
|
||||
topLeft: Radius.circular(16),
|
||||
topRight: Radius.circular(16),
|
||||
),
|
||||
),
|
||||
child: !_showActions
|
||||
? SizedBox()
|
||||
? const SizedBox()
|
||||
: ListView(
|
||||
shrinkWrap: true,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 24.0,
|
||||
const SizedBox(
|
||||
height: 24,
|
||||
),
|
||||
Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: ChannelName(
|
||||
textStyle:
|
||||
StreamChatTheme.of(context).textTheme.headlineBold,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 5.0,
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
Center(
|
||||
child: ChannelInfo(
|
||||
@@ -64,8 +64,8 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
|
||||
.subtitle,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 17.0,
|
||||
const SizedBox(
|
||||
height: 17,
|
||||
),
|
||||
if (channel.isDistinct && channel.memberCount == 2)
|
||||
Column(
|
||||
@@ -75,16 +75,16 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
|
||||
.firstWhere(
|
||||
(e) => e.user?.id != userAsMember.user?.id)
|
||||
.user!,
|
||||
constraints: BoxConstraints(
|
||||
maxHeight: 64.0,
|
||||
maxWidth: 64.0,
|
||||
constraints: const BoxConstraints(
|
||||
maxHeight: 64,
|
||||
maxWidth: 64,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(32.0),
|
||||
borderRadius: BorderRadius.circular(32),
|
||||
onlineIndicatorConstraints:
|
||||
BoxConstraints.tight(Size(12.0, 12.0)),
|
||||
BoxConstraints.tight(const Size(12, 12)),
|
||||
),
|
||||
SizedBox(
|
||||
height: 6.0,
|
||||
const SizedBox(
|
||||
height: 6,
|
||||
),
|
||||
Text(
|
||||
members
|
||||
@@ -102,50 +102,48 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
|
||||
),
|
||||
if (!(channel.isDistinct && channel.memberCount == 2))
|
||||
Container(
|
||||
height: 94.0,
|
||||
height: 94,
|
||||
alignment: Alignment.center,
|
||||
child: ListView.builder(
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemCount: members.length,
|
||||
shrinkWrap: true,
|
||||
itemBuilder: (context, index) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: Column(
|
||||
children: [
|
||||
UserAvatar(
|
||||
user: members[index].user!,
|
||||
constraints: BoxConstraints.tightFor(
|
||||
height: 64.0,
|
||||
width: 64.0,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(32.0),
|
||||
onlineIndicatorConstraints:
|
||||
BoxConstraints.tight(Size(12.0, 12.0)),
|
||||
itemBuilder: (context, index) => Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
child: Column(
|
||||
children: [
|
||||
UserAvatar(
|
||||
user: members[index].user!,
|
||||
constraints: const BoxConstraints.tightFor(
|
||||
height: 64,
|
||||
width: 64,
|
||||
),
|
||||
SizedBox(
|
||||
height: 6.0,
|
||||
),
|
||||
Text(
|
||||
members[index].user?.name ?? '',
|
||||
style: StreamChatTheme.of(context)
|
||||
.textTheme
|
||||
.footnoteBold,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
borderRadius: BorderRadius.circular(32),
|
||||
onlineIndicatorConstraints:
|
||||
BoxConstraints.tight(Size(12, 12)),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 6,
|
||||
),
|
||||
Text(
|
||||
members[index].user?.name ?? '',
|
||||
style: StreamChatTheme.of(context)
|
||||
.textTheme
|
||||
.footnoteBold,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 24.0,
|
||||
const SizedBox(
|
||||
height: 24,
|
||||
),
|
||||
OptionListTile(
|
||||
leading: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: StreamSvgIcon.user(
|
||||
color: StreamChatTheme.of(context).colorTheme.grey,
|
||||
),
|
||||
@@ -156,7 +154,7 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
|
||||
if (!channel.isDistinct)
|
||||
OptionListTile(
|
||||
leading: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: StreamSvgIcon.userRemove(
|
||||
color: StreamChatTheme.of(context).colorTheme.grey,
|
||||
),
|
||||
@@ -175,7 +173,7 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
|
||||
if (isOwner)
|
||||
OptionListTile(
|
||||
leading: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: StreamSvgIcon.delete(
|
||||
color: StreamChatTheme.of(context).colorTheme.accentRed,
|
||||
),
|
||||
@@ -195,7 +193,7 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
|
||||
),
|
||||
OptionListTile(
|
||||
leading: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: StreamSvgIcon.closeSmall(
|
||||
color: StreamChatTheme.of(context).colorTheme.grey,
|
||||
),
|
||||
|
||||
@@ -144,7 +144,7 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget {
|
||||
actions: actions ??
|
||||
<Widget>[
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 10.0),
|
||||
padding: const EdgeInsets.only(right: 10),
|
||||
child: Center(
|
||||
child: ChannelImage(
|
||||
borderRadius: StreamChatTheme.of(context)
|
||||
@@ -169,7 +169,6 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget {
|
||||
height: preferredSize.height,
|
||||
width: preferredSize.width,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
title ??
|
||||
|
||||
@@ -158,30 +158,29 @@ class ChannelImage extends StatelessWidget {
|
||||
alignment: Alignment.center,
|
||||
fit: StackFit.expand,
|
||||
children: <Widget>[
|
||||
image != null
|
||||
? CachedNetworkImage(
|
||||
imageUrl: image,
|
||||
errorWidget: (_, __, ___) {
|
||||
return Center(
|
||||
child: Text(
|
||||
snapshot.data?.containsKey('name') ?? false
|
||||
? snapshot.data!['name'][0]
|
||||
: '',
|
||||
style: TextStyle(
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
fit: BoxFit.cover,
|
||||
)
|
||||
: StreamChatTheme.of(context).defaultChannelImage(
|
||||
context,
|
||||
channel,
|
||||
),
|
||||
if (image != null)
|
||||
CachedNetworkImage(
|
||||
imageUrl: image,
|
||||
errorWidget: (_, __, ___) {
|
||||
return Center(
|
||||
child: Text(
|
||||
snapshot.data?.containsKey('name') ?? false
|
||||
? snapshot.data!['name'][0]
|
||||
: '',
|
||||
style: TextStyle(
|
||||
color: StreamChatTheme.of(context).colorTheme.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
fit: BoxFit.cover,
|
||||
)
|
||||
else
|
||||
StreamChatTheme.of(context).defaultChannelImage(
|
||||
context,
|
||||
channel,
|
||||
),
|
||||
Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
|
||||
@@ -27,28 +27,26 @@ class ChannelInfo extends StatelessWidget {
|
||||
return StreamBuilder<List<Member>>(
|
||||
stream: channel.state?.membersStream,
|
||||
initialData: channel.state?.members,
|
||||
builder: (context, snapshot) {
|
||||
return ConnectionStatusBuilder(
|
||||
statusBuilder: (context, status) {
|
||||
switch (status) {
|
||||
case ConnectionStatus.connected:
|
||||
return _buildConnectedTitleState(context, snapshot.data);
|
||||
case ConnectionStatus.connecting:
|
||||
return _buildConnectingTitleState(context);
|
||||
case ConnectionStatus.disconnected:
|
||||
return _buildDisconnectedTitleState(context, client);
|
||||
default:
|
||||
return Offstage();
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
builder: (context, snapshot) => ConnectionStatusBuilder(
|
||||
statusBuilder: (context, status) {
|
||||
switch (status) {
|
||||
case ConnectionStatus.connected:
|
||||
return _buildConnectedTitleState(context, snapshot.data);
|
||||
case ConnectionStatus.connecting:
|
||||
return _buildConnectingTitleState(context);
|
||||
case ConnectionStatus.disconnected:
|
||||
return _buildDisconnectedTitleState(context, client);
|
||||
default:
|
||||
return const Offstage();
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildConnectedTitleState(
|
||||
BuildContext context, List<Member>? members) {
|
||||
var alternativeWidget;
|
||||
Widget? alternativeWidget;
|
||||
|
||||
if (channel.memberCount != null && channel.memberCount! > 2) {
|
||||
var text = '${channel.memberCount} Members';
|
||||
@@ -82,7 +80,7 @@ class ChannelInfo extends StatelessWidget {
|
||||
}
|
||||
|
||||
if (!showTypingIndicator) {
|
||||
return alternativeWidget ?? Offstage();
|
||||
return alternativeWidget ?? const Offstage();
|
||||
}
|
||||
|
||||
return TypingIndicator(
|
||||
@@ -92,58 +90,55 @@ class ChannelInfo extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildConnectingTitleState(BuildContext context) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
height: 16,
|
||||
width: 16,
|
||||
child: Center(
|
||||
child: CircularProgressIndicator(),
|
||||
Widget _buildConnectingTitleState(BuildContext context) => Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
height: 16,
|
||||
width: 16,
|
||||
child: const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
Text(
|
||||
'Searching for Network',
|
||||
style: textStyle,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
SizedBox(width: 10),
|
||||
Text(
|
||||
'Searching for Network',
|
||||
style: textStyle,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
Widget _buildDisconnectedTitleState(
|
||||
BuildContext context,
|
||||
StreamChatClient client,
|
||||
) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'Offline...',
|
||||
style: textStyle,
|
||||
),
|
||||
TextButton(
|
||||
style: TextButton.styleFrom(
|
||||
padding: const EdgeInsets.all(0),
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
visualDensity: VisualDensity(
|
||||
horizontal: VisualDensity.minimumDensity,
|
||||
vertical: VisualDensity.minimumDensity,
|
||||
) =>
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'Offline...',
|
||||
style: textStyle,
|
||||
),
|
||||
TextButton(
|
||||
style: TextButton.styleFrom(
|
||||
padding: const EdgeInsets.all(0),
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
visualDensity: const VisualDensity(
|
||||
horizontal: VisualDensity.minimumDensity,
|
||||
vertical: VisualDensity.minimumDensity,
|
||||
),
|
||||
),
|
||||
onPressed: () async {
|
||||
await client.disconnect();
|
||||
await client.connect();
|
||||
},
|
||||
child: Text(
|
||||
'Try Again',
|
||||
style: textStyle?.copyWith(
|
||||
color: StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||
),
|
||||
),
|
||||
),
|
||||
onPressed: () async {
|
||||
await client.disconnect();
|
||||
await client.connect();
|
||||
},
|
||||
child: Text(
|
||||
'Try Again',
|
||||
style: textStyle?.copyWith(
|
||||
color: StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -168,8 +168,8 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
|
||||
return SvgPicture.asset(
|
||||
'svgs/icon_pen_write.svg',
|
||||
package: 'stream_chat_flutter',
|
||||
width: 24.0,
|
||||
height: 24.0,
|
||||
width: 24,
|
||||
height: 24,
|
||||
color: color,
|
||||
);
|
||||
},
|
||||
|
||||
@@ -54,7 +54,7 @@ typedef ViewInfoCallback = void Function(Channel);
|
||||
/// Modify it to change the widget appearance.
|
||||
class ChannelListView extends StatefulWidget {
|
||||
/// Instantiate a new ChannelListView
|
||||
ChannelListView({
|
||||
const ChannelListView({
|
||||
Key? key,
|
||||
this.filter,
|
||||
this.options,
|
||||
@@ -248,7 +248,7 @@ class _ChannelListViewState extends State<ChannelListView> {
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: StreamSvgIcon.message(
|
||||
size: 136,
|
||||
color: StreamChatTheme.of(context)
|
||||
@@ -257,7 +257,7 @@ class _ChannelListViewState extends State<ChannelListView> {
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: Text(
|
||||
'Let’s start chatting!',
|
||||
style: StreamChatTheme.of(context).textTheme.headline,
|
||||
@@ -265,7 +265,7 @@ class _ChannelListViewState extends State<ChannelListView> {
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 8.0,
|
||||
vertical: 8,
|
||||
horizontal: 52,
|
||||
),
|
||||
child: Text(
|
||||
@@ -340,7 +340,7 @@ class _ChannelListViewState extends State<ChannelListView> {
|
||||
highlightColor: StreamChatTheme.of(context).colorTheme.whiteSmoke,
|
||||
child: Column(
|
||||
children: [
|
||||
SizedBox(height: 4.0),
|
||||
SizedBox(height: 4),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
@@ -358,7 +358,7 @@ class _ChannelListViewState extends State<ChannelListView> {
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: 16.0,
|
||||
height: 16,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -441,7 +441,7 @@ class _ChannelListViewState extends State<ChannelListView> {
|
||||
WidgetSpan(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
right: 2.0,
|
||||
right: 2,
|
||||
),
|
||||
child: Icon(Icons.error_outline),
|
||||
),
|
||||
@@ -477,7 +477,6 @@ class _ChannelListViewState extends State<ChannelListView> {
|
||||
enabled: widget.swipeToAction,
|
||||
actionPane: SlidableBehindActionPane(),
|
||||
actionExtentRatio: 0.12,
|
||||
closeOnScroll: true,
|
||||
secondaryActions: <Widget>[
|
||||
IconSlideAction(
|
||||
color: backgroundColor,
|
||||
@@ -589,7 +588,6 @@ class _ChannelListViewState extends State<ChannelListView> {
|
||||
key: ValueKey<String>('CHANNEL-${channel.id}'),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
ChannelImage(
|
||||
channel: channel,
|
||||
@@ -634,7 +632,7 @@ class _ChannelListViewState extends State<ChannelListView> {
|
||||
.accentRed
|
||||
.withOpacity(.2),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
child: Center(
|
||||
child: Text('Error loading channels'),
|
||||
),
|
||||
@@ -644,7 +642,7 @@ class _ChannelListViewState extends State<ChannelListView> {
|
||||
return snapshot.data!
|
||||
? Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: const CircularProgressIndicator(),
|
||||
),
|
||||
)
|
||||
@@ -653,7 +651,7 @@ class _ChannelListViewState extends State<ChannelListView> {
|
||||
}
|
||||
|
||||
Widget _separatorBuilder(context, i) {
|
||||
var effect = StreamChatTheme.of(context).colorTheme.borderBottom;
|
||||
final effect = StreamChatTheme.of(context).colorTheme.borderBottom;
|
||||
|
||||
return Container(
|
||||
height: 1,
|
||||
|
||||
@@ -47,7 +47,7 @@ class ChannelPreview extends StatelessWidget {
|
||||
/// Widget rendering the sending indicator, by default it uses the [SendingIndicator] widget
|
||||
final Widget? sendingIndicator;
|
||||
|
||||
ChannelPreview({
|
||||
const ChannelPreview({
|
||||
required this.channel,
|
||||
Key? key,
|
||||
this.onTap,
|
||||
@@ -128,7 +128,7 @@ class ChannelPreview extends StatelessWidget {
|
||||
if (lastMessage?.user?.id ==
|
||||
StreamChat.of(context).user?.id) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(right: 4.0),
|
||||
padding: const EdgeInsets.only(right: 4),
|
||||
child: SendingIndicator(
|
||||
message: lastMessage!,
|
||||
size: channelPreviewTheme.indicatorIconSize,
|
||||
@@ -167,7 +167,7 @@ class ChannelPreview extends StatelessWidget {
|
||||
String stringDate;
|
||||
final now = DateTime.now();
|
||||
|
||||
var startOfDay = DateTime(now.year, now.month, now.day);
|
||||
final startOfDay = DateTime(now.year, now.month, now.day);
|
||||
|
||||
if (lastMessageAt.millisecondsSinceEpoch >=
|
||||
startOfDay.millisecondsSinceEpoch) {
|
||||
@@ -298,7 +298,7 @@ class ChannelPreview extends StatelessWidget {
|
||||
));
|
||||
} else {
|
||||
resList.add(TextSpan(
|
||||
text: e == textList.last ? '$e' : '$e ',
|
||||
text: e == textList.last ? e : '$e ',
|
||||
style: normalTextStyle,
|
||||
));
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ class DeletedMessage extends StatelessWidget {
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 8.0,
|
||||
vertical: 8,
|
||||
horizontal: 16,
|
||||
),
|
||||
child: Transform(
|
||||
|
||||
@@ -150,7 +150,7 @@ class _FullScreenMediaState extends State<FullScreenMedia>
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 50.0,
|
||||
vertical: 50,
|
||||
),
|
||||
child: Chewie(
|
||||
controller: controller.chewieController!,
|
||||
|
||||
@@ -113,8 +113,8 @@ class GroupImage extends StatelessWidget {
|
||||
child: Container(
|
||||
color: selectionColor ??
|
||||
StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||
height: 64.0,
|
||||
width: 64.0,
|
||||
height: 64,
|
||||
width: 64,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(selectionThickness),
|
||||
child: avatar,
|
||||
|
||||
@@ -82,47 +82,45 @@ class _ImageFooterState extends State<ImageFooter> {
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
!showShareButton
|
||||
? Container(
|
||||
width: 48,
|
||||
)
|
||||
: IconButton(
|
||||
icon: StreamSvgIcon.iconShare(
|
||||
size: 24.0,
|
||||
color: StreamChatTheme.of(context).colorTheme.black,
|
||||
),
|
||||
onPressed: () async {
|
||||
final attachment =
|
||||
widget.mediaAttachments[widget.currentPage];
|
||||
final url = attachment.imageUrl ??
|
||||
attachment.assetUrl ??
|
||||
attachment.thumbUrl!;
|
||||
final type = attachment.type == 'image'
|
||||
? 'jpg'
|
||||
: url.split('?').first.split('.').last;
|
||||
final request =
|
||||
await HttpClient().getUrl(Uri.parse(url));
|
||||
final response = await request.close();
|
||||
final bytes =
|
||||
await consolidateHttpClientResponseBytes(response);
|
||||
final tmpPath = await getTemporaryDirectory();
|
||||
final filePath =
|
||||
'${tmpPath.path}/${attachment.id}.$type';
|
||||
final file = File(filePath);
|
||||
await file.writeAsBytes(bytes);
|
||||
await Share.shareFiles(
|
||||
[filePath],
|
||||
mimeTypes: [
|
||||
'image/$type',
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
if (!showShareButton)
|
||||
Container(
|
||||
width: 48,
|
||||
)
|
||||
else
|
||||
IconButton(
|
||||
icon: StreamSvgIcon.iconShare(
|
||||
size: 24,
|
||||
color: StreamChatTheme.of(context).colorTheme.black,
|
||||
),
|
||||
onPressed: () async {
|
||||
final attachment =
|
||||
widget.mediaAttachments[widget.currentPage];
|
||||
final url = attachment.imageUrl ??
|
||||
attachment.assetUrl ??
|
||||
attachment.thumbUrl!;
|
||||
final type = attachment.type == 'image'
|
||||
? 'jpg'
|
||||
: url.split('?').first.split('.').last;
|
||||
final request = await HttpClient().getUrl(Uri.parse(url));
|
||||
final response = await request.close();
|
||||
final bytes =
|
||||
await consolidateHttpClientResponseBytes(response);
|
||||
final tmpPath = await getTemporaryDirectory();
|
||||
final filePath = '${tmpPath.path}/${attachment.id}.$type';
|
||||
final file = File(filePath);
|
||||
await file.writeAsBytes(bytes);
|
||||
await Share.shareFiles(
|
||||
[filePath],
|
||||
mimeTypes: [
|
||||
'image/$type',
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
InkWell(
|
||||
onTap: widget.onTitleTap,
|
||||
child: Container(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
@@ -156,12 +154,12 @@ class _ImageFooterState extends State<ImageFooter> {
|
||||
isScrollControlled: true,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(16.0),
|
||||
topRight: Radius.circular(16.0),
|
||||
topLeft: Radius.circular(16),
|
||||
topRight: Radius.circular(16),
|
||||
),
|
||||
),
|
||||
builder: (context) {
|
||||
final crossAxisCount = 3;
|
||||
const crossAxisCount = 3;
|
||||
final noOfRowToShowInitially =
|
||||
widget.mediaAttachments.length > crossAxisCount ? 2 : 1;
|
||||
final size = MediaQuery.of(context).size;
|
||||
@@ -181,7 +179,7 @@ class _ImageFooterState extends State<ImageFooter> {
|
||||
children: [
|
||||
Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Text(
|
||||
'Photos',
|
||||
style: StreamChatTheme.of(context)
|
||||
@@ -209,8 +207,8 @@ class _ImageFooterState extends State<ImageFooter> {
|
||||
padding: const EdgeInsets.all(1),
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: crossAxisCount,
|
||||
mainAxisSpacing: 2.0,
|
||||
crossAxisSpacing: 2.0,
|
||||
mainAxisSpacing: 2,
|
||||
crossAxisSpacing: 2,
|
||||
),
|
||||
itemBuilder: (context, index) {
|
||||
Widget media;
|
||||
@@ -230,7 +228,7 @@ class _ImageFooterState extends State<ImageFooter> {
|
||||
media = InkWell(
|
||||
onTap: () => widget.mediaSelectedCallBack!(index),
|
||||
child: AspectRatio(
|
||||
aspectRatio: 1.0,
|
||||
aspectRatio: 1,
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: attachment.imageUrl ??
|
||||
attachment.assetUrl ??
|
||||
@@ -246,7 +244,7 @@ class _ImageFooterState extends State<ImageFooter> {
|
||||
media,
|
||||
if (widget.message.user != null)
|
||||
Padding(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
padding: EdgeInsets.all(8),
|
||||
child: Container(
|
||||
clipBehavior: Clip.antiAlias,
|
||||
decoration: BoxDecoration(
|
||||
@@ -254,7 +252,7 @@ class _ImageFooterState extends State<ImageFooter> {
|
||||
color: Colors.white.withOpacity(0.6),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
blurRadius: 8.0,
|
||||
blurRadius: 8,
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.black
|
||||
@@ -287,7 +285,7 @@ class _ImageFooterState extends State<ImageFooter> {
|
||||
|
||||
/// Sends the current message
|
||||
Future sendMessage() async {
|
||||
var text = _messageController.text.trim();
|
||||
final text = _messageController.text.trim();
|
||||
|
||||
final attachments = widget.message.attachments;
|
||||
|
||||
@@ -311,10 +309,10 @@ class _ImageFooterState extends State<ImageFooter> {
|
||||
class IconClipper extends CustomClipper<Path> {
|
||||
@override
|
||||
Path getClip(Size size) {
|
||||
var leftX = size.width / 5;
|
||||
var rightX = 4 * size.width / 5;
|
||||
var topY = size.height / 5;
|
||||
var bottomY = 4 * size.height / 5;
|
||||
final leftX = size.width / 5;
|
||||
final rightX = 4 * size.width / 5;
|
||||
final topY = size.height / 5;
|
||||
final bottomY = 4 * size.height / 5;
|
||||
|
||||
final path = Path();
|
||||
path.moveTo(leftX, topY);
|
||||
@@ -322,7 +320,7 @@ class IconClipper extends CustomClipper<Path> {
|
||||
path.lineTo(rightX, bottomY);
|
||||
path.lineTo(rightX, topY);
|
||||
path.lineTo(leftX, topY);
|
||||
path.lineTo(0.0, 0.0);
|
||||
path.lineTo(0, 0);
|
||||
path.close();
|
||||
return path;
|
||||
}
|
||||
|
||||
@@ -27,22 +27,19 @@ class ImageGroup extends StatelessWidget {
|
||||
direction: Axis.vertical,
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
flex: 1,
|
||||
fit: FlexFit.tight,
|
||||
child: Flex(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
direction: Axis.horizontal,
|
||||
children: [
|
||||
Flexible(
|
||||
flex: 1,
|
||||
fit: FlexFit.tight,
|
||||
child: _buildImage(context, 0),
|
||||
),
|
||||
Flexible(
|
||||
flex: 1,
|
||||
fit: FlexFit.tight,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 2.0),
|
||||
padding: const EdgeInsets.only(left: 2),
|
||||
child: _buildImage(context, 1),
|
||||
),
|
||||
),
|
||||
@@ -52,24 +49,21 @@ class ImageGroup extends StatelessWidget {
|
||||
if (images.length >= 3)
|
||||
Flexible(
|
||||
fit: FlexFit.tight,
|
||||
flex: 1,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 2.0),
|
||||
padding: const EdgeInsets.only(top: 2),
|
||||
child: Flex(
|
||||
direction: Axis.horizontal,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
fit: FlexFit.tight,
|
||||
flex: 1,
|
||||
child: _buildImage(context, 2),
|
||||
),
|
||||
if (images.length >= 4)
|
||||
Flexible(
|
||||
fit: FlexFit.tight,
|
||||
flex: 1,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 2.0),
|
||||
padding: const EdgeInsets.only(left: 2),
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: <Widget>[
|
||||
|
||||
@@ -53,7 +53,7 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget {
|
||||
? IconButton(
|
||||
icon: StreamSvgIcon.close(
|
||||
color: StreamChatTheme.of(context).colorTheme.black,
|
||||
size: 24.0,
|
||||
size: 24,
|
||||
),
|
||||
onPressed: onBackPressed,
|
||||
)
|
||||
@@ -79,7 +79,6 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget {
|
||||
height: preferredSize.height,
|
||||
width: preferredSize.width,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
|
||||
@@ -11,7 +11,7 @@ class InfoTile extends StatelessWidget {
|
||||
final TextStyle? textStyle;
|
||||
final Color? backgroundColor;
|
||||
|
||||
InfoTile({
|
||||
const InfoTile({
|
||||
required this.message,
|
||||
required this.child,
|
||||
required this.showMessage,
|
||||
@@ -28,7 +28,7 @@ class InfoTile extends StatelessWidget {
|
||||
portalAnchor: tileAnchor ?? Alignment.topCenter,
|
||||
childAnchor: childAnchor ?? Alignment.bottomCenter,
|
||||
portal: Container(
|
||||
height: 25.0,
|
||||
height: 25,
|
||||
color: backgroundColor ??
|
||||
StreamChatTheme.of(context).colorTheme.grey.withOpacity(0.9),
|
||||
child: Center(
|
||||
|
||||
@@ -54,7 +54,7 @@ class _MediaListViewState extends State<MediaListView> {
|
||||
) {
|
||||
final media = _media.elementAt(position);
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 1.0, vertical: 1.0),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 1, vertical: 1),
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
if (widget.onSelect != null) {
|
||||
@@ -64,7 +64,7 @@ class _MediaListViewState extends State<MediaListView> {
|
||||
child: Stack(
|
||||
children: [
|
||||
AspectRatio(
|
||||
aspectRatio: 1.0,
|
||||
aspectRatio: 1,
|
||||
child: FadeInImage(
|
||||
fadeInDuration: Duration(milliseconds: 300),
|
||||
placeholder: AssetImage(
|
||||
@@ -144,9 +144,7 @@ class _MediaListViewState extends State<MediaListView> {
|
||||
}
|
||||
|
||||
void _getMedia() async {
|
||||
final assetList = await PhotoManager.getAssetPathList(
|
||||
hasAll: true,
|
||||
).then((value) {
|
||||
final assetList = await PhotoManager.getAssetPathList().then((value) {
|
||||
if (value.isNotEmpty == true) {
|
||||
return value.singleWhere((element) => element.isAll);
|
||||
}
|
||||
@@ -178,7 +176,7 @@ class MediaThumbnailProvider extends ImageProvider<MediaThumbnailProvider> {
|
||||
ImageStreamCompleter load(key, decode) {
|
||||
return MultiFrameImageStreamCompleter(
|
||||
codec: _loadAsync(key, decode),
|
||||
scale: 1.0,
|
||||
scale: 1,
|
||||
informationCollector: () sync* {
|
||||
yield ErrorDescription('Id: ${media.id}');
|
||||
},
|
||||
|
||||
@@ -20,7 +20,7 @@ class MentionTile extends StatelessWidget {
|
||||
/// Widget at the end of tile
|
||||
final Widget? trailing;
|
||||
|
||||
MentionTile(
|
||||
const MentionTile(
|
||||
this.member, {
|
||||
this.title,
|
||||
this.subtitle,
|
||||
@@ -31,12 +31,11 @@ class MentionTile extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
height: 56.0,
|
||||
height: 56,
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 16.0,
|
||||
width: 16,
|
||||
),
|
||||
leading ??
|
||||
UserAvatar(
|
||||
@@ -49,7 +48,7 @@ class MentionTile extends StatelessWidget {
|
||||
user: member.user!,
|
||||
),
|
||||
SizedBox(
|
||||
width: 8.0,
|
||||
width: 8,
|
||||
),
|
||||
Expanded(
|
||||
child: Align(
|
||||
@@ -60,13 +59,13 @@ class MentionTile extends StatelessWidget {
|
||||
children: [
|
||||
title ??
|
||||
Text(
|
||||
'${member.user!.name}',
|
||||
member.user!.name,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: StreamChatTheme.of(context).textTheme.bodyBold,
|
||||
),
|
||||
SizedBox(
|
||||
height: 2.0,
|
||||
height: 2,
|
||||
),
|
||||
subtitle ??
|
||||
Text(
|
||||
@@ -88,8 +87,8 @@ class MentionTile extends StatelessWidget {
|
||||
trailing ??
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
right: 18.0,
|
||||
left: 8.0,
|
||||
right: 18,
|
||||
left: 8,
|
||||
),
|
||||
child: StreamSvgIcon.mentions(
|
||||
color: StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||
|
||||
@@ -119,7 +119,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
||||
),
|
||||
if (_showActions)
|
||||
TweenAnimationBuilder<double>(
|
||||
tween: Tween(begin: 0.0, end: 1.0),
|
||||
tween: Tween(begin: 0, end: 1),
|
||||
duration: Duration(milliseconds: 300),
|
||||
curve: Curves.easeInOutBack,
|
||||
builder: (context, val, snapshot) {
|
||||
@@ -128,7 +128,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
||||
child: Center(
|
||||
child: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: Column(
|
||||
crossAxisAlignment: widget.reverse
|
||||
? CrossAxisAlignment.end
|
||||
@@ -146,7 +146,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
||||
: (divFactor > 1.0
|
||||
? 0.0
|
||||
: -(1.0 - divFactor)),
|
||||
0.0),
|
||||
0),
|
||||
child: ReactionPicker(
|
||||
message: widget.message,
|
||||
),
|
||||
@@ -166,7 +166,6 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
||||
messageTheme: widget.messageTheme,
|
||||
showReactions: false,
|
||||
showUsername: false,
|
||||
showThreadReplyIndicator: false,
|
||||
showReplyMessage: false,
|
||||
showUserAvatar: widget.showUserAvatar,
|
||||
attachmentPadding: EdgeInsets.all(
|
||||
@@ -176,7 +175,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
||||
translateUserAvatar: false,
|
||||
padding: const EdgeInsets.all(0),
|
||||
textPadding: EdgeInsets.symmetric(
|
||||
vertical: 8.0,
|
||||
vertical: 8,
|
||||
horizontal: widget.message.text!.isOnlyEmoji
|
||||
? 0
|
||||
: 16.0,
|
||||
@@ -185,7 +184,6 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
||||
widget.showReactions &&
|
||||
(widget.message.status ==
|
||||
MessageSendingStatus.sent),
|
||||
showInChannelIndicator: false,
|
||||
showSendingIndicator: false,
|
||||
shape: widget.messageShape,
|
||||
attachmentShape: widget.attachmentShape,
|
||||
@@ -269,7 +267,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
||||
messageAction.onTap?.call(widget.message);
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 11.0, horizontal: 16.0),
|
||||
padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16),
|
||||
child: Row(
|
||||
children: [
|
||||
messageAction.leading ?? Offstage(),
|
||||
@@ -289,7 +287,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
||||
title: 'Flag Message',
|
||||
icon: StreamSvgIcon.flag(
|
||||
color: StreamChatTheme.of(context).colorTheme.accentRed,
|
||||
size: 24.0,
|
||||
size: 24,
|
||||
),
|
||||
question:
|
||||
'Do you want to send a copy of this message to a\nmoderator for further investigation?',
|
||||
@@ -305,7 +303,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
||||
context,
|
||||
icon: StreamSvgIcon.flag(
|
||||
color: theme.colorTheme.accentRed,
|
||||
size: 24.0,
|
||||
size: 24,
|
||||
),
|
||||
details: 'The message has been reported to a moderator.',
|
||||
title: 'Message flagged',
|
||||
@@ -317,7 +315,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
||||
context,
|
||||
icon: StreamSvgIcon.flag(
|
||||
color: theme.colorTheme.accentRed,
|
||||
size: 24.0,
|
||||
size: 24,
|
||||
),
|
||||
details: 'The message has been reported to a moderator.',
|
||||
title: 'Message flagged',
|
||||
@@ -339,7 +337,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
||||
title: 'Delete message',
|
||||
icon: StreamSvgIcon.flag(
|
||||
color: StreamChatTheme.of(context).colorTheme.accentRed,
|
||||
size: 24.0,
|
||||
size: 24,
|
||||
),
|
||||
question: 'Are you sure you want to permanently delete this\nmessage?',
|
||||
okText: 'DELETE',
|
||||
@@ -365,7 +363,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
||||
context,
|
||||
icon: StreamSvgIcon.error(
|
||||
color: StreamChatTheme.of(context).colorTheme.accentRed,
|
||||
size: 24.0,
|
||||
size: 24,
|
||||
),
|
||||
details: 'The operation couldn\'t be completed.',
|
||||
title: 'Something went wrong',
|
||||
@@ -382,7 +380,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
||||
}
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 11.0, horizontal: 16.0),
|
||||
padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16),
|
||||
child: Row(
|
||||
children: [
|
||||
StreamSvgIcon.reply(
|
||||
@@ -401,9 +399,9 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
||||
|
||||
Widget _buildFlagButton(BuildContext context) {
|
||||
return InkWell(
|
||||
onTap: () => _showFlagDialog(),
|
||||
onTap: _showFlagDialog,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 11.0, horizontal: 16.0),
|
||||
padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16),
|
||||
child: Row(
|
||||
children: [
|
||||
StreamSvgIcon.iconFlag(
|
||||
@@ -424,9 +422,9 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
||||
final isDeleteFailed =
|
||||
widget.message.status == MessageSendingStatus.failed_delete;
|
||||
return InkWell(
|
||||
onTap: () => _showDeleteDialog(),
|
||||
onTap: _showDeleteDialog,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 11.0, horizontal: 16.0),
|
||||
padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16),
|
||||
child: Row(
|
||||
children: [
|
||||
StreamSvgIcon.delete(
|
||||
@@ -453,7 +451,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 11.0, horizontal: 16.0),
|
||||
padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16),
|
||||
child: Row(
|
||||
children: [
|
||||
StreamSvgIcon.copy(
|
||||
@@ -478,7 +476,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
||||
_showEditBottomSheet(context);
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 11.0, horizontal: 16.0),
|
||||
padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16),
|
||||
child: Row(
|
||||
children: [
|
||||
StreamSvgIcon.edit(
|
||||
@@ -509,7 +507,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
||||
}
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 11.0, horizontal: 16.0),
|
||||
padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16),
|
||||
child: Row(
|
||||
children: [
|
||||
StreamSvgIcon.circleUp(
|
||||
@@ -555,7 +553,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: StreamSvgIcon.edit(
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
@@ -574,16 +572,17 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
||||
],
|
||||
),
|
||||
),
|
||||
widget.editMessageInputBuilder != null
|
||||
? widget.editMessageInputBuilder!(context, widget.message)
|
||||
: MessageInput(
|
||||
editMessage: widget.message,
|
||||
preMessageSending: (m) {
|
||||
FocusScope.of(context).unfocus();
|
||||
Navigator.pop(context);
|
||||
return m;
|
||||
},
|
||||
),
|
||||
if (widget.editMessageInputBuilder != null)
|
||||
widget.editMessageInputBuilder!(context, widget.message)
|
||||
else
|
||||
MessageInput(
|
||||
editMessage: widget.message,
|
||||
preMessageSending: (m) {
|
||||
FocusScope.of(context).unfocus();
|
||||
Navigator.pop(context);
|
||||
return m;
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -600,7 +599,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
||||
}
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 11.0, horizontal: 16.0),
|
||||
padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16),
|
||||
child: Row(
|
||||
children: [
|
||||
StreamSvgIcon.thread(
|
||||
|
||||
@@ -109,7 +109,7 @@ const _kMaxAttachmentSize = 20971520; // 20MB in Bytes
|
||||
/// Modify it to change the widget appearance.
|
||||
class MessageInput extends StatefulWidget {
|
||||
/// Instantiate a new MessageInput
|
||||
MessageInput({
|
||||
const MessageInput({
|
||||
Key? key,
|
||||
this.onMessageSent,
|
||||
this.preMessageSending,
|
||||
@@ -306,7 +306,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: StreamSvgIcon.reply(
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
@@ -326,15 +326,15 @@ class MessageInputState extends State<MessageInput> {
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
child: _buildTextField(context),
|
||||
),
|
||||
if (widget.parentMessage != null && !widget.hideSendAsDm)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
right: 12.0,
|
||||
left: 12.0,
|
||||
bottom: 12.0,
|
||||
right: 12,
|
||||
left: 12,
|
||||
bottom: 12,
|
||||
),
|
||||
child: _buildDmCheckbox(),
|
||||
),
|
||||
@@ -356,7 +356,6 @@ class MessageInputState extends State<MessageInput> {
|
||||
Flex _buildTextField(BuildContext context) {
|
||||
return Flex(
|
||||
direction: Axis.horizontal,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
if (!_commandEnabled && widget.actionsLocation == ActionsLocation.left)
|
||||
_buildExpandActionsButton(),
|
||||
@@ -371,7 +370,6 @@ class MessageInputState extends State<MessageInput> {
|
||||
|
||||
Widget _buildDmCheckbox() {
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
height: 16,
|
||||
@@ -407,7 +405,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
? CrossFadeState.showFirst
|
||||
: CrossFadeState.showSecond,
|
||||
firstChild: StreamSvgIcon.check(
|
||||
size: 16.0,
|
||||
size: 16,
|
||||
color: StreamChatTheme.of(context).colorTheme.white,
|
||||
),
|
||||
secondChild: SizedBox(
|
||||
@@ -420,7 +418,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12.0),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
child: Text(
|
||||
'Also send as direct message',
|
||||
style: StreamChatTheme.of(context).textTheme.footnote.copyWith(
|
||||
@@ -456,7 +454,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
|
||||
Widget _buildExpandActionsButton() {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
child: AnimatedCrossFade(
|
||||
crossFadeState: _actionsShrunk
|
||||
? CrossFadeState.showFirst
|
||||
@@ -464,7 +462,6 @@ class MessageInputState extends State<MessageInput> {
|
||||
firstChild: IconButton(
|
||||
onPressed: () => setState(() => _actionsShrunk = false),
|
||||
icon: Transform.rotate(
|
||||
alignment: Alignment.center,
|
||||
angle: (widget.actionsLocation == ActionsLocation.right ||
|
||||
widget.actionsLocation == ActionsLocation.rightInside)
|
||||
? pi
|
||||
@@ -484,7 +481,6 @@ class MessageInputState extends State<MessageInput> {
|
||||
),
|
||||
secondChild: FittedBox(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: <Widget>[
|
||||
if (!widget.disableAttachments) _buildAttachmentButton(),
|
||||
@@ -510,10 +506,10 @@ class MessageInputState extends State<MessageInput> {
|
||||
Expanded _buildTextInput(BuildContext context) {
|
||||
final theme = StreamChatTheme.of(context);
|
||||
final margin = (widget.sendButtonLocation == SendButtonLocation.inside
|
||||
? const EdgeInsets.only(right: 8.0)
|
||||
? const EdgeInsets.only(right: 8)
|
||||
: EdgeInsets.zero) +
|
||||
(widget.actionsLocation != ActionsLocation.left
|
||||
? const EdgeInsets.only(left: 8.0)
|
||||
? const EdgeInsets.only(left: 8)
|
||||
: EdgeInsets.zero);
|
||||
return Expanded(
|
||||
child: Center(
|
||||
@@ -545,7 +541,6 @@ class MessageInputState extends State<MessageInput> {
|
||||
child: TextField(
|
||||
key: Key('messageInputText'),
|
||||
enabled: _inputEnabled,
|
||||
minLines: null,
|
||||
maxLines: null,
|
||||
onSubmitted: (_) => sendMessage(),
|
||||
keyboardType: widget.keyboardType,
|
||||
@@ -607,7 +602,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: Container(
|
||||
constraints: BoxConstraints.tight(Size(64, 24)),
|
||||
decoration: BoxDecoration(
|
||||
@@ -620,7 +615,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
children: [
|
||||
StreamSvgIcon.lightning(
|
||||
color: Colors.white,
|
||||
size: 16.0,
|
||||
size: 16,
|
||||
),
|
||||
Text(
|
||||
_chosenCommand?.name.toUpperCase() ?? '',
|
||||
@@ -640,7 +635,6 @@ class MessageInputState extends State<MessageInput> {
|
||||
: (widget.actionsLocation == ActionsLocation.leftInside
|
||||
? Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
_buildExpandActionsButton(),
|
||||
],
|
||||
@@ -650,11 +644,10 @@ class MessageInputState extends State<MessageInput> {
|
||||
prefixIconConstraints: BoxConstraints.tightFor(height: 40),
|
||||
suffixIcon: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
if (_commandEnabled)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8.0),
|
||||
padding: const EdgeInsets.only(right: 8),
|
||||
child: IconButton(
|
||||
icon: StreamSvgIcon.closeSmall(),
|
||||
splashRadius: 24,
|
||||
@@ -776,7 +769,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
|
||||
void _checkCommands(String s, BuildContext context) {
|
||||
if (s.startsWith('/')) {
|
||||
var matchedCommandsList = StreamChannel.of(context)
|
||||
final matchedCommandsList = StreamChannel.of(context)
|
||||
.channel
|
||||
.config
|
||||
?.commands
|
||||
@@ -825,19 +818,18 @@ class MessageInputState extends State<MessageInput> {
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: TweenAnimationBuilder<double>(
|
||||
tween: Tween(begin: 0.0, end: 1.0),
|
||||
tween: Tween(begin: 0, end: 1),
|
||||
duration: Duration(milliseconds: 300),
|
||||
curve: Curves.easeInOutExpo,
|
||||
builder: (context, val, wid) {
|
||||
return Transform.scale(
|
||||
alignment: Alignment.center,
|
||||
scale: val,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: Card(
|
||||
elevation: 2.0,
|
||||
elevation: 2,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
color: StreamChatTheme.of(context).colorTheme.white,
|
||||
clipBehavior: Clip.antiAlias,
|
||||
@@ -845,20 +837,19 @@ class MessageInputState extends State<MessageInput> {
|
||||
constraints: BoxConstraints.loose(Size.fromHeight(400)),
|
||||
decoration: BoxDecoration(
|
||||
color: StreamChatTheme.of(context).colorTheme.white,
|
||||
borderRadius: BorderRadius.circular(8.0)),
|
||||
borderRadius: BorderRadius.circular(8)),
|
||||
child: ListView(
|
||||
padding: const EdgeInsets.all(0),
|
||||
shrinkWrap: true,
|
||||
children: [
|
||||
if (commands.isNotEmpty)
|
||||
Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(left: 0.0, top: 8.0),
|
||||
padding: const EdgeInsets.only(top: 8),
|
||||
child: Row(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8.0,
|
||||
horizontal: 8,
|
||||
),
|
||||
child: StreamSvgIcon.lightning(
|
||||
color: StreamChatTheme.of(context)
|
||||
@@ -879,7 +870,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 10.0,
|
||||
height: 10,
|
||||
),
|
||||
...commands
|
||||
.map(
|
||||
@@ -888,19 +879,19 @@ class MessageInputState extends State<MessageInput> {
|
||||
_setCommand(c);
|
||||
},
|
||||
child: Container(
|
||||
height: 40.0,
|
||||
height: 40,
|
||||
child: Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 16.0,
|
||||
width: 16,
|
||||
),
|
||||
_buildCommandIcon(c.name),
|
||||
SizedBox(
|
||||
width: 8.0,
|
||||
width: 8,
|
||||
),
|
||||
Text.rich(
|
||||
TextSpan(
|
||||
text: '${c.name.capitalize()}',
|
||||
text: c.name.capitalize(),
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold),
|
||||
children: [
|
||||
@@ -987,10 +978,8 @@ class MessageInputState extends State<MessageInput> {
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
IconButton(
|
||||
iconSize: 24,
|
||||
icon: StreamSvgIcon.pictures(
|
||||
color: _getIconColor(0),
|
||||
),
|
||||
@@ -1010,11 +999,10 @@ class MessageInputState extends State<MessageInput> {
|
||||
onPressed: !_attachmentContainsFile && _attachments.isNotEmpty
|
||||
? null
|
||||
: () {
|
||||
pickFile(DefaultAttachmentTypes.file, false);
|
||||
pickFile(DefaultAttachmentTypes.file);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
iconSize: 24,
|
||||
icon: StreamSvgIcon.camera(
|
||||
color: _getIconColor(2),
|
||||
),
|
||||
@@ -1026,7 +1014,6 @@ class MessageInputState extends State<MessageInput> {
|
||||
),
|
||||
IconButton(
|
||||
padding: const EdgeInsets.all(0),
|
||||
iconSize: 24,
|
||||
icon: StreamSvgIcon.record(
|
||||
color: _getIconColor(3),
|
||||
),
|
||||
@@ -1052,22 +1039,22 @@ class MessageInputState extends State<MessageInput> {
|
||||
decoration: BoxDecoration(
|
||||
color: StreamChatTheme.of(context).colorTheme.white,
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(16.0),
|
||||
topRight: Radius.circular(16.0),
|
||||
topLeft: Radius.circular(16),
|
||||
topRight: Radius.circular(16),
|
||||
),
|
||||
),
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
child: Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: Container(
|
||||
width: 40.0,
|
||||
height: 4.0,
|
||||
width: 40,
|
||||
height: 4,
|
||||
decoration: BoxDecoration(
|
||||
color:
|
||||
StreamChatTheme.of(context).colorTheme.whiteSmoke,
|
||||
borderRadius: BorderRadius.circular(4.0),
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -1080,7 +1067,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: StreamChatTheme.of(context).colorTheme.white,
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: _PickerWidget(
|
||||
filePickerIndex: _filePickerIndex,
|
||||
@@ -1159,7 +1146,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
return CircleAvatar(
|
||||
radius: 12,
|
||||
child: StreamSvgIcon.giphyIcon(
|
||||
size: 24.0,
|
||||
size: 24,
|
||||
),
|
||||
);
|
||||
case 'ban':
|
||||
@@ -1167,7 +1154,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||
radius: 12,
|
||||
child: StreamSvgIcon.iconUserDelete(
|
||||
size: 16.0,
|
||||
size: 16,
|
||||
color: Colors.white,
|
||||
),
|
||||
);
|
||||
@@ -1176,7 +1163,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||
radius: 12,
|
||||
child: StreamSvgIcon.flag(
|
||||
size: 14.0,
|
||||
size: 14,
|
||||
color: Colors.white,
|
||||
),
|
||||
);
|
||||
@@ -1186,7 +1173,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
radius: 12,
|
||||
child: ClipOval(
|
||||
child: StreamSvgIcon.imgur(
|
||||
size: 24.0,
|
||||
size: 24,
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -1195,7 +1182,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||
radius: 12,
|
||||
child: StreamSvgIcon.mute(
|
||||
size: 16.0,
|
||||
size: 16,
|
||||
color: Colors.white,
|
||||
),
|
||||
);
|
||||
@@ -1204,7 +1191,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||
radius: 12,
|
||||
child: StreamSvgIcon.userAdd(
|
||||
size: 16.0,
|
||||
size: 16,
|
||||
color: Colors.white,
|
||||
),
|
||||
);
|
||||
@@ -1213,7 +1200,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||
radius: 12,
|
||||
child: StreamSvgIcon.volumeUp(
|
||||
size: 16.0,
|
||||
size: 16,
|
||||
color: Colors.white,
|
||||
),
|
||||
);
|
||||
@@ -1222,7 +1209,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||
radius: 12,
|
||||
child: StreamSvgIcon.lightning(
|
||||
size: 16.0,
|
||||
size: 16,
|
||||
color: Colors.white,
|
||||
),
|
||||
);
|
||||
@@ -1263,18 +1250,18 @@ class MessageInputState extends State<MessageInput> {
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: TweenAnimationBuilder<double>(
|
||||
tween: Tween(begin: 0.0, end: 1.0),
|
||||
tween: Tween(begin: 0, end: 1),
|
||||
duration: Duration(milliseconds: 300),
|
||||
curve: Curves.easeInOutExpo,
|
||||
builder: (context, val, wid) {
|
||||
return Transform.scale(
|
||||
scale: val,
|
||||
child: Card(
|
||||
margin: EdgeInsets.all(8.0),
|
||||
elevation: 2.0,
|
||||
margin: EdgeInsets.all(8),
|
||||
elevation: 2,
|
||||
color: StreamChatTheme.of(context).colorTheme.white,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: Container(
|
||||
@@ -1291,7 +1278,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
shrinkWrap: true,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 8.0,
|
||||
height: 8,
|
||||
),
|
||||
...snapshot.data!
|
||||
.where((it) => it.user != null)
|
||||
@@ -1333,7 +1320,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
},
|
||||
).toList(),
|
||||
SizedBox(
|
||||
height: 8.0,
|
||||
height: 8,
|
||||
),
|
||||
],
|
||||
);
|
||||
@@ -1361,7 +1348,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
|
||||
final emojis = _emojiNames
|
||||
.where((e) => e.contains(query))
|
||||
.map((e) => Emoji.byName(e))
|
||||
.map(Emoji.byName)
|
||||
.where((e) => e != null);
|
||||
|
||||
if (emojis.isEmpty) {
|
||||
@@ -1377,11 +1364,11 @@ class MessageInputState extends State<MessageInput> {
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: Card(
|
||||
margin: EdgeInsets.all(8.0),
|
||||
elevation: 2.0,
|
||||
margin: EdgeInsets.all(8),
|
||||
elevation: 2,
|
||||
color: StreamChatTheme.of(context).colorTheme.white,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: Container(
|
||||
@@ -1390,7 +1377,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
spreadRadius: -8,
|
||||
blurRadius: 5.0,
|
||||
blurRadius: 5,
|
||||
offset: Offset(0, -4),
|
||||
),
|
||||
],
|
||||
@@ -1403,12 +1390,11 @@ class MessageInputState extends State<MessageInput> {
|
||||
itemBuilder: (context, i) {
|
||||
if (i == 0) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(left: 8.0, top: 8.0),
|
||||
padding: const EdgeInsets.only(left: 8, top: 8),
|
||||
child: Row(
|
||||
children: [
|
||||
Padding(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
child: StreamSvgIcon.smile(
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
@@ -1516,7 +1502,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(8, 8, 8, 0),
|
||||
child: LimitedBox(
|
||||
maxHeight: 136.0,
|
||||
maxHeight: 136,
|
||||
child: ListView(
|
||||
reverse: true,
|
||||
shrinkWrap: true,
|
||||
@@ -1524,16 +1510,15 @@ class MessageInputState extends State<MessageInput> {
|
||||
.map<Widget>(
|
||||
(e) => ClipRRect(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: FileAttachment(
|
||||
message: Message(), // dummy message
|
||||
attachment: e,
|
||||
size: Size(
|
||||
MediaQuery.of(context).size.width * 0.65,
|
||||
56.0,
|
||||
56,
|
||||
),
|
||||
trailing: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: _buildRemoveButton(e),
|
||||
),
|
||||
),
|
||||
@@ -1547,18 +1532,17 @@ class MessageInputState extends State<MessageInput> {
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(8, 8, 8, 0),
|
||||
child: LimitedBox(
|
||||
maxHeight: 104.0,
|
||||
maxHeight: 104,
|
||||
child: ListView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
children: remainingAttachments
|
||||
.map<Widget>(
|
||||
(attachment) => ClipRRect(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
AspectRatio(
|
||||
aspectRatio: 1.0,
|
||||
aspectRatio: 1,
|
||||
child: Container(
|
||||
height: 104,
|
||||
width: 104,
|
||||
@@ -1593,7 +1577,6 @@ class MessageInputState extends State<MessageInput> {
|
||||
elevation: 0,
|
||||
highlightElevation: 0,
|
||||
focusElevation: 0,
|
||||
disabledElevation: 0,
|
||||
hoverElevation: 0,
|
||||
onPressed: () {
|
||||
setState(() => _attachments.remove(attachment.id));
|
||||
@@ -1803,7 +1786,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
leading: Icon(Icons.image),
|
||||
title: Text('Upload a photo'),
|
||||
onTap: () {
|
||||
pickFile(DefaultAttachmentTypes.image, false);
|
||||
pickFile(DefaultAttachmentTypes.image);
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
@@ -1811,7 +1794,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
leading: Icon(Icons.video_library),
|
||||
title: Text('Upload a video'),
|
||||
onTap: () {
|
||||
pickFile(DefaultAttachmentTypes.video, false);
|
||||
pickFile(DefaultAttachmentTypes.video);
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
@@ -1837,7 +1820,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
leading: Icon(Icons.insert_drive_file),
|
||||
title: Text('Upload a file'),
|
||||
onTap: () {
|
||||
pickFile(DefaultAttachmentTypes.file, false);
|
||||
pickFile(DefaultAttachmentTypes.file);
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
@@ -1967,7 +1950,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
|
||||
Widget _buildIdleSendButton(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: StreamSvgIcon(
|
||||
assetName: _getIdleSendIcon(),
|
||||
color:
|
||||
@@ -1978,7 +1961,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
|
||||
Widget _buildSendButton(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: IconButton(
|
||||
onPressed: sendMessage,
|
||||
padding: const EdgeInsets.all(0),
|
||||
@@ -2112,44 +2095,44 @@ class MessageInputState extends State<MessageInput> {
|
||||
context: context,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(16.0),
|
||||
topRight: Radius.circular(16.0),
|
||||
topLeft: Radius.circular(16),
|
||||
topRight: Radius.circular(16),
|
||||
)),
|
||||
builder: (context) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 26.0,
|
||||
height: 26,
|
||||
),
|
||||
StreamSvgIcon.error(
|
||||
color: StreamChatTheme.of(context).colorTheme.accentRed,
|
||||
size: 24.0,
|
||||
size: 24,
|
||||
),
|
||||
SizedBox(
|
||||
height: 26.0,
|
||||
height: 26,
|
||||
),
|
||||
Text(
|
||||
'Something went wrong',
|
||||
style: StreamChatTheme.of(context).textTheme.headlineBold,
|
||||
),
|
||||
SizedBox(
|
||||
height: 7.0,
|
||||
height: 7,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Text(
|
||||
description,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 36.0,
|
||||
height: 36,
|
||||
),
|
||||
Container(
|
||||
color:
|
||||
StreamChatTheme.of(context).colorTheme.black.withOpacity(.08),
|
||||
height: 1.0,
|
||||
height: 1,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
@@ -2345,7 +2328,7 @@ class __PickerWidgetState extends State<_PickerWidget> {
|
||||
color: StreamChatTheme.of(context).colorTheme.grey),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
SizedBox(height: 6.0),
|
||||
SizedBox(height: 6),
|
||||
Center(
|
||||
child: Text(
|
||||
'Allow access to your gallery',
|
||||
|
||||
@@ -111,7 +111,7 @@ class MessageDetails {
|
||||
/// Modify it to change the widget appearance.
|
||||
class MessageListView extends StatefulWidget {
|
||||
/// Instantiate a new MessageListView
|
||||
MessageListView({
|
||||
const MessageListView({
|
||||
Key? key,
|
||||
this.showScrollToBottom = true,
|
||||
this.messageBuilder,
|
||||
@@ -418,7 +418,6 @@ class _MessageListViewState extends State<MessageListView> {
|
||||
child: ScrollablePositionedList.separated(
|
||||
key: ValueKey(initialIndex! + initialAlignment!),
|
||||
itemPositionsListener: _itemPositionListener,
|
||||
addAutomaticKeepAlives: true,
|
||||
initialScrollIndex: initialIndex ?? 0,
|
||||
initialAlignment: initialAlignment ?? 0,
|
||||
physics: widget.scrollPhysics,
|
||||
@@ -437,7 +436,7 @@ class _MessageListViewState extends State<MessageListView> {
|
||||
StreamChatTheme.of(context).colorTheme.bgGradient,
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: Text(
|
||||
'$replyCount ${replyCount == 1 ? 'Reply' : 'Replies'}',
|
||||
textAlign: TextAlign.center,
|
||||
@@ -464,7 +463,7 @@ class _MessageListViewState extends State<MessageListView> {
|
||||
dateTime: nextMessage.createdAt.toLocal(),
|
||||
);
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 12.0),
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
child: divider,
|
||||
);
|
||||
}
|
||||
@@ -554,7 +553,7 @@ class _MessageListViewState extends State<MessageListView> {
|
||||
),
|
||||
if (widget.showScrollToBottom) _buildScrollToBottom(),
|
||||
Positioned(
|
||||
top: 20.0,
|
||||
top: 20,
|
||||
child: ValueListenableBuilder<Iterable<ItemPosition>>(
|
||||
valueListenable: _itemPositionListener.itemPositions,
|
||||
builder: (context, values, _) {
|
||||
@@ -660,7 +659,7 @@ class _MessageListViewState extends State<MessageListView> {
|
||||
top: -10,
|
||||
child: CircleAvatar(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(3.0),
|
||||
padding: const EdgeInsets.all(3),
|
||||
child: Text(
|
||||
'$unreadCount',
|
||||
style: TextStyle(
|
||||
@@ -712,7 +711,7 @@ class _MessageListViewState extends State<MessageListView> {
|
||||
}
|
||||
return Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: const CircularProgressIndicator(),
|
||||
),
|
||||
);
|
||||
@@ -799,8 +798,6 @@ class _MessageListViewState extends State<MessageListView> {
|
||||
final isOnlyEmoji = message.text!.isOnlyEmoji;
|
||||
|
||||
return MessageWidget(
|
||||
showThreadReplyIndicator: false,
|
||||
showInChannelIndicator: false,
|
||||
showReplyMessage: false,
|
||||
showResendMessage: false,
|
||||
showThreadReplyMessage: false,
|
||||
@@ -810,7 +807,7 @@ class _MessageListViewState extends State<MessageListView> {
|
||||
message: message,
|
||||
reverse: isMyMessage,
|
||||
showUsername: !isMyMessage,
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
padding: const EdgeInsets.all(8),
|
||||
showSendingIndicator: false,
|
||||
onThreadTap: _onThreadTap as void Function(Message)?,
|
||||
borderRadiusGeometry: BorderRadius.only(
|
||||
@@ -820,7 +817,7 @@ class _MessageListViewState extends State<MessageListView> {
|
||||
bottomRight: Radius.circular(16),
|
||||
),
|
||||
textPadding: EdgeInsets.symmetric(
|
||||
vertical: 8.0,
|
||||
vertical: 8,
|
||||
horizontal: isOnlyEmoji ? 0 : 16.0,
|
||||
),
|
||||
borderSide: isMyMessage || isOnlyEmoji ? BorderSide.none : null,
|
||||
@@ -940,7 +937,7 @@ class _MessageListViewState extends State<MessageListView> {
|
||||
message: message,
|
||||
reverse: isMyMessage,
|
||||
showReactions: !message.isDeleted,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
showInChannelIndicator: showInChannelIndicator,
|
||||
showThreadReplyIndicator: showThreadReplyIndicator,
|
||||
showUsername: showUsername,
|
||||
@@ -997,7 +994,7 @@ class _MessageListViewState extends State<MessageListView> {
|
||||
bottomRight: Radius.circular(16),
|
||||
),
|
||||
textPadding: EdgeInsets.symmetric(
|
||||
vertical: 8.0,
|
||||
vertical: 8,
|
||||
horizontal: isOnlyEmoji ? 0 : 16.0,
|
||||
),
|
||||
messageTheme: isMyMessage
|
||||
@@ -1069,7 +1066,7 @@ class _MessageListViewState extends State<MessageListView> {
|
||||
);
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 4.0),
|
||||
padding: const EdgeInsets.only(top: 4),
|
||||
child: child,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -59,7 +59,7 @@ class MessageReactionsModal extends StatelessWidget {
|
||||
: (roughSentenceSize == 0 ? 1 : (roughSentenceSize / roughMaxSize));
|
||||
|
||||
return TweenAnimationBuilder<double>(
|
||||
tween: Tween(begin: 0.0, end: 1.0),
|
||||
tween: Tween(begin: 0, end: 1),
|
||||
duration: Duration(milliseconds: 300),
|
||||
curve: Curves.easeInOutBack,
|
||||
builder: (context, val, snapshot) {
|
||||
@@ -86,7 +86,7 @@ class MessageReactionsModal extends StatelessWidget {
|
||||
child: Center(
|
||||
child: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
@@ -102,7 +102,7 @@ class MessageReactionsModal extends StatelessWidget {
|
||||
: (divFactor > 1.0
|
||||
? 0.0
|
||||
: -(1.0 - divFactor)),
|
||||
0.0),
|
||||
0),
|
||||
child: ReactionPicker(
|
||||
message: message,
|
||||
),
|
||||
@@ -121,7 +121,6 @@ class MessageReactionsModal extends StatelessWidget {
|
||||
showReactions: false,
|
||||
showUsername: false,
|
||||
showUserAvatar: showUserAvatar,
|
||||
showThreadReplyIndicator: false,
|
||||
showTimestamp: false,
|
||||
translateUserAvatar: false,
|
||||
showSendingIndicator: false,
|
||||
@@ -133,9 +132,8 @@ class MessageReactionsModal extends StatelessWidget {
|
||||
attachmentPadding: EdgeInsets.all(
|
||||
hasFileAttachment ? 4 : 2,
|
||||
),
|
||||
showInChannelIndicator: false,
|
||||
textPadding: EdgeInsets.symmetric(
|
||||
vertical: 8.0,
|
||||
vertical: 8,
|
||||
horizontal:
|
||||
message.text!.isOnlyEmoji ? 0 : 16.0,
|
||||
),
|
||||
@@ -184,7 +182,6 @@ class MessageReactionsModal extends StatelessWidget {
|
||||
child: Wrap(
|
||||
spacing: 16,
|
||||
runSpacing: 16,
|
||||
alignment: WrapAlignment.start,
|
||||
children: message.latestReactions!
|
||||
.map((e) => _buildReaction(
|
||||
e,
|
||||
@@ -214,8 +211,6 @@ class MessageReactionsModal extends StatelessWidget {
|
||||
)),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Stack(
|
||||
clipBehavior: Clip.none,
|
||||
|
||||
@@ -147,8 +147,8 @@ class MessageSearchItem extends StatelessWidget {
|
||||
List<Attachment> attachments,
|
||||
TextStyle? normalTextStyle,
|
||||
TextStyle? mentionsTextStyle) {
|
||||
var textList = text.split(' ');
|
||||
var resList = <TextSpan>[];
|
||||
final textList = text.split(' ');
|
||||
final resList = <TextSpan>[];
|
||||
for (var e in textList) {
|
||||
if (mentions.isNotEmpty &&
|
||||
mentions.any((element) => '@${element.name}' == e)) {
|
||||
@@ -166,7 +166,7 @@ class MessageSearchItem extends StatelessWidget {
|
||||
));
|
||||
} else {
|
||||
resList.add(TextSpan(
|
||||
text: e == textList.last ? '$e' : '$e ',
|
||||
text: e == textList.last ? e : '$e ',
|
||||
style: normalTextStyle,
|
||||
));
|
||||
}
|
||||
|
||||
@@ -189,10 +189,7 @@ class _MessageSearchListViewState extends State<MessageSearchListView> {
|
||||
},
|
||||
);
|
||||
},
|
||||
childBuilder: widget.childBuilder ??
|
||||
(list) {
|
||||
return _buildListView(list);
|
||||
},
|
||||
childBuilder: widget.childBuilder ?? _buildListView,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -228,7 +225,7 @@ class _MessageSearchListViewState extends State<MessageSearchListView> {
|
||||
.accentRed
|
||||
.withOpacity(.2),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
child: Center(
|
||||
child: Text('Error loading messages'),
|
||||
),
|
||||
|
||||
@@ -201,8 +201,8 @@ class MessageWidget extends StatefulWidget {
|
||||
this.readList,
|
||||
this.padding,
|
||||
this.textPadding = const EdgeInsets.symmetric(
|
||||
horizontal: 16.0,
|
||||
vertical: 8.0,
|
||||
horizontal: 16,
|
||||
vertical: 8,
|
||||
),
|
||||
this.attachmentPadding = EdgeInsets.zero,
|
||||
this.allRead = false,
|
||||
@@ -211,8 +211,7 @@ class MessageWidget extends StatefulWidget {
|
||||
this.onAttachmentTap,
|
||||
}) : attachmentBuilders = {
|
||||
'image': (context, message, attachments) {
|
||||
var border = RoundedRectangleBorder(
|
||||
side: BorderSide.none,
|
||||
final border = RoundedRectangleBorder(
|
||||
borderRadius: attachmentBorderRadiusGeometry ?? BorderRadius.zero,
|
||||
);
|
||||
|
||||
@@ -267,8 +266,7 @@ class MessageWidget extends StatefulWidget {
|
||||
);
|
||||
},
|
||||
'video': (context, message, attachments) {
|
||||
var border = RoundedRectangleBorder(
|
||||
side: BorderSide.none,
|
||||
final border = RoundedRectangleBorder(
|
||||
borderRadius: attachmentBorderRadiusGeometry ?? BorderRadius.zero,
|
||||
);
|
||||
|
||||
@@ -302,7 +300,6 @@ class MessageWidget extends StatefulWidget {
|
||||
},
|
||||
'giphy': (context, message, attachments) {
|
||||
final border = RoundedRectangleBorder(
|
||||
side: BorderSide.none,
|
||||
borderRadius: attachmentBorderRadiusGeometry ?? BorderRadius.zero,
|
||||
);
|
||||
|
||||
@@ -329,7 +326,7 @@ class MessageWidget extends StatefulWidget {
|
||||
);
|
||||
},
|
||||
'file': (context, message, attachments) {
|
||||
var border = RoundedRectangleBorder(
|
||||
final border = RoundedRectangleBorder(
|
||||
side: attachmentBorderSide ??
|
||||
BorderSide(
|
||||
color: StreamChatTheme.of(context).colorTheme.greyWhisper,
|
||||
@@ -426,7 +423,7 @@ class _MessageWidgetState extends State<MessageWidget>
|
||||
super.build(context);
|
||||
final avatarWidth =
|
||||
widget.messageTheme.avatarTheme?.constraints.maxWidth ?? 40;
|
||||
var leftPadding =
|
||||
final leftPadding =
|
||||
widget.showUserAvatar != DisplayWidget.gone ? avatarWidth + 8.5 : 0.5;
|
||||
|
||||
return Material(
|
||||
@@ -460,7 +457,6 @@ class _MessageWidgetState extends State<MessageWidget>
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
@@ -481,8 +477,8 @@ class _MessageWidgetState extends State<MessageWidget>
|
||||
BoxConstraints(maxWidth: 22 * 6.0),
|
||||
child: _buildReactionIndicator(context),
|
||||
),
|
||||
portalAnchor: Alignment(-1.0, -1.0),
|
||||
childAnchor: Alignment(1, -1.0),
|
||||
portalAnchor: Alignment(-1, -1),
|
||||
childAnchor: Alignment(1, -1),
|
||||
child: Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
@@ -526,7 +522,7 @@ class _MessageWidgetState extends State<MessageWidget>
|
||||
)
|
||||
: Card(
|
||||
clipBehavior: Clip.antiAlias,
|
||||
elevation: 0.0,
|
||||
elevation: 0,
|
||||
margin: EdgeInsets.symmetric(
|
||||
horizontal: (isFailedState
|
||||
? 15.0
|
||||
@@ -650,9 +646,9 @@ class _MessageWidgetState extends State<MessageWidget>
|
||||
children: [
|
||||
StreamSvgIcon.eye(
|
||||
color: StreamChatTheme.of(context).colorTheme.grey,
|
||||
size: 16.0,
|
||||
size: 16,
|
||||
),
|
||||
SizedBox(width: 8.0),
|
||||
SizedBox(width: 8),
|
||||
Text(
|
||||
'Only visible to you',
|
||||
style: StreamChatTheme.of(context)
|
||||
@@ -665,7 +661,7 @@ class _MessageWidgetState extends State<MessageWidget>
|
||||
);
|
||||
}
|
||||
|
||||
var children = <Widget>[];
|
||||
final children = <Widget>[];
|
||||
|
||||
final threadParticipants = widget.message.threadParticipants?.take(2);
|
||||
final showThreadParticipants = threadParticipants?.isNotEmpty == true;
|
||||
@@ -757,18 +753,18 @@ class _MessageWidgetState extends State<MessageWidget>
|
||||
return mappedChild;
|
||||
},
|
||||
),
|
||||
].insertBetween(const SizedBox(width: 8.0)),
|
||||
].insertBetween(const SizedBox(width: 8)),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildUrlAttachment() {
|
||||
var urlAttachment = widget.message.attachments
|
||||
final urlAttachment = widget.message.attachments
|
||||
.firstWhere((element) => element.ogScrapeUrl != null);
|
||||
|
||||
var host = Uri.parse(urlAttachment.ogScrapeUrl!).host;
|
||||
var splitList = host.split('.');
|
||||
var hostName = splitList.length == 3 ? splitList[1] : splitList[0];
|
||||
var hostDisplayName = urlAttachment.authorName?.capitalize() ??
|
||||
final host = Uri.parse(urlAttachment.ogScrapeUrl!).host;
|
||||
final splitList = host.split('.');
|
||||
final hostName = splitList.length == 3 ? splitList[1] : splitList[0];
|
||||
final hostDisplayName = urlAttachment.authorName?.capitalize() ??
|
||||
getWebsiteName(hostName.toLowerCase()) ??
|
||||
hostName.capitalize();
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ class OptionListTile extends StatelessWidget {
|
||||
final Color? separatorColor;
|
||||
final TextStyle? titleTextStyle;
|
||||
|
||||
OptionListTile({
|
||||
const OptionListTile({
|
||||
this.title,
|
||||
this.leading,
|
||||
this.trailing,
|
||||
@@ -29,12 +29,12 @@ class OptionListTile extends StatelessWidget {
|
||||
Container(
|
||||
color: separatorColor ??
|
||||
StreamChatTheme.of(context).colorTheme.greyGainsboro,
|
||||
height: 1.0,
|
||||
height: 1,
|
||||
),
|
||||
Material(
|
||||
color: tileColor ?? StreamChatTheme.of(context).colorTheme.white,
|
||||
child: Container(
|
||||
height: 63.0,
|
||||
height: 63,
|
||||
child: InkWell(
|
||||
onTap: onTap,
|
||||
child: Row(
|
||||
@@ -42,7 +42,7 @@ class OptionListTile extends StatelessWidget {
|
||||
if (leading != null) Center(child: leading),
|
||||
if (leading == null)
|
||||
SizedBox(
|
||||
width: 16.0,
|
||||
width: 16,
|
||||
),
|
||||
Expanded(
|
||||
flex: 4,
|
||||
@@ -62,7 +62,7 @@ class OptionListTile extends StatelessWidget {
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: 16.0),
|
||||
padding: const EdgeInsets.only(right: 16),
|
||||
child: Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: trailing ?? Container(),
|
||||
|
||||
@@ -87,7 +87,7 @@ class QuotedMessageWidget extends StatelessWidget {
|
||||
final GestureTapCallback? onTap;
|
||||
|
||||
///
|
||||
QuotedMessageWidget({
|
||||
const QuotedMessageWidget({
|
||||
Key? key,
|
||||
required this.message,
|
||||
required this.messageTheme,
|
||||
@@ -237,7 +237,7 @@ class QuotedMessageWidget extends StatelessWidget {
|
||||
|
||||
ShapeBorder _getDefaultShape(BuildContext context) {
|
||||
return RoundedRectangleBorder(
|
||||
side: BorderSide(width: 0.0, color: Colors.transparent),
|
||||
side: BorderSide(width: 0, color: Colors.transparent),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -40,7 +40,6 @@ class ReactionBubble extends StatelessWidget {
|
||||
alignment: Alignment.center,
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
fit: StackFit.loose,
|
||||
children: [
|
||||
Transform.translate(
|
||||
offset: Offset(reverse ? offset : -offset, 0),
|
||||
@@ -115,7 +114,7 @@ class ReactionBubble extends StatelessWidget {
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 4.0,
|
||||
horizontal: 4,
|
||||
),
|
||||
child: reactionIcon != null
|
||||
? StreamSvgIcon(
|
||||
@@ -239,9 +238,9 @@ class ReactionBubblePainter extends CustomPainter {
|
||||
..strokeWidth = 1
|
||||
..style = PaintingStyle.stroke;
|
||||
|
||||
final dy = -2.2;
|
||||
final startAngle = 1.1;
|
||||
final sweepAngle = 1.2;
|
||||
const dy = -2.2;
|
||||
const startAngle = 1.1;
|
||||
const sweepAngle = 1.2;
|
||||
final path = Path();
|
||||
path.addArc(
|
||||
Rect.fromCircle(
|
||||
@@ -259,9 +258,9 @@ class ReactionBubblePainter extends CustomPainter {
|
||||
..color = color
|
||||
..strokeWidth = 1;
|
||||
|
||||
final dy = -2.2;
|
||||
final startAngle = 1;
|
||||
final sweepAngle = 1.3;
|
||||
const dy = -2.2;
|
||||
const startAngle = 1;
|
||||
const sweepAngle = 1.3;
|
||||
final path = Path();
|
||||
path.addArc(
|
||||
Rect.fromCircle(
|
||||
@@ -280,9 +279,9 @@ class ReactionBubblePainter extends CustomPainter {
|
||||
..strokeWidth = 1
|
||||
..style = PaintingStyle.fill;
|
||||
|
||||
final dy = -2.2;
|
||||
final startAngle = 1.1;
|
||||
final sweepAngle = 1.2;
|
||||
const dy = -2.2;
|
||||
const startAngle = 1.1;
|
||||
const sweepAngle = 1.2;
|
||||
final path = Path();
|
||||
path.addArc(
|
||||
Rect.fromCircle(
|
||||
|
||||
@@ -49,7 +49,7 @@ class _ReactionPickerState extends State<ReactionPicker>
|
||||
}
|
||||
|
||||
return TweenAnimationBuilder<double>(
|
||||
tween: Tween(begin: 0.0, end: 1.0),
|
||||
tween: Tween(begin: 0, end: 1),
|
||||
curve: Curves.easeInOutBack,
|
||||
duration: Duration(milliseconds: 500),
|
||||
builder: (context, val, wid) {
|
||||
@@ -61,8 +61,8 @@ class _ReactionPickerState extends State<ReactionPicker>
|
||||
clipBehavior: Clip.hardEdge,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16.0,
|
||||
vertical: 8.0,
|
||||
horizontal: 16,
|
||||
vertical: 8,
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@@ -74,7 +74,7 @@ class _ReactionPickerState extends State<ReactionPicker>
|
||||
?.indexWhere((reaction) =>
|
||||
reaction.type == reactionIcon.type) ??
|
||||
-1;
|
||||
var index = reactionIcons.indexOf(reactionIcon);
|
||||
final index = reactionIcons.indexOf(reactionIcon);
|
||||
|
||||
return ConstrainedBox(
|
||||
constraints: BoxConstraints.tightFor(
|
||||
@@ -83,8 +83,6 @@ class _ReactionPickerState extends State<ReactionPicker>
|
||||
),
|
||||
child: RawMaterialButton(
|
||||
elevation: 0,
|
||||
padding: const EdgeInsets.all(0),
|
||||
clipBehavior: Clip.none,
|
||||
shape: ContinuousRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
@@ -110,7 +108,6 @@ class _ReactionPickerState extends State<ReactionPicker>
|
||||
animation: animations[index],
|
||||
builder: (context, val) {
|
||||
return Transform.scale(
|
||||
alignment: Alignment.center,
|
||||
scale: animations[index].value,
|
||||
child: StreamSvgIcon(
|
||||
assetName: reactionIcon.assetName,
|
||||
|
||||
@@ -43,7 +43,7 @@ class StreamChat extends StatefulWidget {
|
||||
/// upon the [Event.type]
|
||||
final EventHandler? onBackgroundEventReceived;
|
||||
|
||||
StreamChat({
|
||||
const StreamChat({
|
||||
Key? key,
|
||||
required this.client,
|
||||
required this.child,
|
||||
|
||||
@@ -13,7 +13,7 @@ import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||
class StreamChatTheme extends InheritedWidget {
|
||||
final StreamChatThemeData data;
|
||||
|
||||
StreamChatTheme({
|
||||
const StreamChatTheme({
|
||||
Key? key,
|
||||
required this.data,
|
||||
required Widget child,
|
||||
@@ -237,7 +237,7 @@ class StreamChatThemeData {
|
||||
lastMessageAt: textTheme.footnote.copyWith(
|
||||
color: colorTheme.black.withOpacity(.5),
|
||||
),
|
||||
indicatorIconSize: 16.0),
|
||||
indicatorIconSize: 16),
|
||||
channelListHeaderTheme: ChannelListHeaderTheme(
|
||||
avatarTheme: AvatarTheme(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
@@ -543,17 +543,13 @@ class ColorTheme {
|
||||
stops: [0, 1],
|
||||
),
|
||||
this.borderTop = const Effect(
|
||||
sigmaX: 0,
|
||||
sigmaY: -1,
|
||||
color: Color(0xff000000),
|
||||
blur: 0.0,
|
||||
alpha: 0.08),
|
||||
sigmaX: 0, sigmaY: -1, color: Color(0xff000000), blur: 0, alpha: 0.08),
|
||||
this.borderBottom = const Effect(
|
||||
sigmaX: 0, sigmaY: 1, color: Color(0xff000000), blur: 0.0, alpha: 0.08),
|
||||
sigmaX: 0, sigmaY: 1, color: Color(0xff000000), blur: 0, alpha: 0.08),
|
||||
this.shadowIconButton = const Effect(
|
||||
sigmaX: 0, sigmaY: 2, color: Color(0xff000000), alpha: 0.5, blur: 4.0),
|
||||
sigmaX: 0, sigmaY: 2, color: Color(0xff000000), alpha: 0.5, blur: 4),
|
||||
this.modalShadow = const Effect(
|
||||
sigmaX: 0, sigmaY: 0, color: Color(0xff000000), alpha: 1, blur: 8.0),
|
||||
sigmaX: 0, sigmaY: 0, color: Color(0xff000000), alpha: 1, blur: 8),
|
||||
}) : brightness = Brightness.light;
|
||||
|
||||
ColorTheme.dark({
|
||||
@@ -572,28 +568,28 @@ class ColorTheme {
|
||||
sigmaX: 0,
|
||||
sigmaY: -1,
|
||||
color: Color(0xff141924),
|
||||
blur: 0.0,
|
||||
blur: 0,
|
||||
),
|
||||
this.borderBottom = const Effect(
|
||||
sigmaX: 0,
|
||||
sigmaY: 1,
|
||||
color: Color(0xff141924),
|
||||
blur: 0.0,
|
||||
alpha: 1.0,
|
||||
blur: 0,
|
||||
alpha: 1,
|
||||
),
|
||||
this.shadowIconButton = const Effect(
|
||||
sigmaX: 0,
|
||||
sigmaY: 2,
|
||||
color: Color(0xff000000),
|
||||
alpha: 0.5,
|
||||
blur: 4.0,
|
||||
blur: 4,
|
||||
),
|
||||
this.modalShadow = const Effect(
|
||||
sigmaX: 0,
|
||||
sigmaY: 0,
|
||||
color: Color(0xff000000),
|
||||
alpha: 1,
|
||||
blur: 8.0,
|
||||
blur: 8,
|
||||
),
|
||||
this.highlight = const Color(0xff302d22),
|
||||
this.overlay = const Color.fromRGBO(0, 0, 0, 0.4),
|
||||
|
||||
@@ -13,7 +13,7 @@ class StreamNeumorphicButton extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
margin: EdgeInsets.all(8.0),
|
||||
margin: EdgeInsets.all(8),
|
||||
height: 40,
|
||||
width: 40,
|
||||
decoration: BoxDecoration(
|
||||
@@ -22,15 +22,12 @@ class StreamNeumorphicButton extends StatelessWidget {
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.grey.shade700,
|
||||
offset: Offset(0, 1.0),
|
||||
offset: Offset(0, 1),
|
||||
blurRadius: 0.5,
|
||||
spreadRadius: 0,
|
||||
),
|
||||
BoxShadow(
|
||||
color: Colors.white,
|
||||
offset: Offset.zero,
|
||||
blurRadius: 0.5,
|
||||
spreadRadius: 0,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -25,7 +25,6 @@ class StreamSvgIcon extends StatelessWidget {
|
||||
width: width,
|
||||
height: height,
|
||||
color: color,
|
||||
alignment: Alignment.center,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ class Swipeable extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _SwipeableState extends State<Swipeable> with TickerProviderStateMixin {
|
||||
double _dragExtent = 0.0;
|
||||
double _dragExtent = 0;
|
||||
late AnimationController _moveController;
|
||||
late AnimationController _iconMoveController;
|
||||
late Animation<Offset> _moveAnimation;
|
||||
@@ -45,15 +45,15 @@ class _SwipeableState extends State<Swipeable> with TickerProviderStateMixin {
|
||||
AnimationController(duration: _animationDuration, vsync: this);
|
||||
_iconMoveController =
|
||||
AnimationController(duration: _animationDuration, vsync: this);
|
||||
_moveAnimation = Tween<Offset>(begin: Offset.zero, end: Offset(1.0, 0.0))
|
||||
_moveAnimation = Tween<Offset>(begin: Offset.zero, end: Offset(1, 0))
|
||||
.animate(_moveController);
|
||||
_iconTransitionAnimation =
|
||||
Tween<Offset>(begin: Offset(-0.1, 0.0), end: Offset(0.4, 0.0))
|
||||
Tween<Offset>(begin: Offset(-0.1, 0), end: Offset(0.4, 0))
|
||||
.animate(_moveController);
|
||||
_iconFadeAnimation =
|
||||
Tween<double>(begin: 0.7, end: 1.0).animate(_iconMoveController);
|
||||
Tween<double>(begin: 0.7, end: 1).animate(_iconMoveController);
|
||||
|
||||
final controllerValue = 0.0;
|
||||
const controllerValue = 0.0;
|
||||
_moveController.animateTo(controllerValue);
|
||||
_iconMoveController.animateTo(controllerValue);
|
||||
}
|
||||
@@ -77,19 +77,19 @@ class _SwipeableState extends State<Swipeable> with TickerProviderStateMixin {
|
||||
|
||||
if (_dragExtent.isNegative) return;
|
||||
|
||||
var movePastThresholdPixels = widget.threshold;
|
||||
final movePastThresholdPixels = widget.threshold;
|
||||
var newPos = _dragExtent.abs() / context.size!.width;
|
||||
|
||||
if (_dragExtent.abs() > movePastThresholdPixels) {
|
||||
// how many "thresholds" past the threshold we are. 1 = the threshold 2
|
||||
// = two thresholds.
|
||||
var n = _dragExtent.abs() / movePastThresholdPixels;
|
||||
final n = _dragExtent.abs() / movePastThresholdPixels;
|
||||
|
||||
// Take the number of thresholds past the threshold, and reduce this
|
||||
// number
|
||||
var reducedThreshold = math.pow(n, 0.3);
|
||||
final reducedThreshold = math.pow(n, 0.3);
|
||||
|
||||
var adjustedPixelPos = movePastThresholdPixels * reducedThreshold;
|
||||
final adjustedPixelPos = movePastThresholdPixels * reducedThreshold;
|
||||
newPos = adjustedPixelPos / context.size!.width;
|
||||
|
||||
if (_dragExtent > 0 && !_pastThreshold) {
|
||||
@@ -111,8 +111,8 @@ class _SwipeableState extends State<Swipeable> with TickerProviderStateMixin {
|
||||
}
|
||||
|
||||
void _handleDragEnd(DragEndDetails details) {
|
||||
_moveController.animateTo(0.0, duration: _animationDuration);
|
||||
_iconMoveController.animateTo(0.0, duration: _animationDuration);
|
||||
_moveController.animateTo(0, duration: _animationDuration);
|
||||
_iconMoveController.animateTo(0, duration: _animationDuration);
|
||||
_dragExtent = 0.0;
|
||||
if (_pastThreshold && widget.onSwipeEnd != null) {
|
||||
widget.onSwipeEnd!();
|
||||
|
||||
@@ -118,7 +118,6 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget {
|
||||
child: Container(
|
||||
height: preferredSize.height,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
title ??
|
||||
@@ -133,7 +132,6 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget {
|
||||
subtitle ??
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
|
||||
@@ -33,8 +33,8 @@ class UnreadIndicator extends StatelessWidget {
|
||||
.unreadCounterColor,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 5.0,
|
||||
right: 5.0,
|
||||
left: 5,
|
||||
right: 5,
|
||||
top: 2,
|
||||
bottom: 1,
|
||||
),
|
||||
|
||||
@@ -10,7 +10,7 @@ class UploadProgressIndicator extends StatelessWidget {
|
||||
final bool showBackground;
|
||||
final TextStyle? textStyle;
|
||||
|
||||
UploadProgressIndicator({
|
||||
const UploadProgressIndicator({
|
||||
Key? key,
|
||||
required this.uploaded,
|
||||
required this.total,
|
||||
|
||||
@@ -8,12 +8,12 @@ class UrlAttachment extends StatelessWidget {
|
||||
final String hostDisplayName;
|
||||
final EdgeInsets textPadding;
|
||||
|
||||
UrlAttachment({
|
||||
const UrlAttachment({
|
||||
required this.urlAttachment,
|
||||
required this.hostDisplayName,
|
||||
this.textPadding = const EdgeInsets.symmetric(
|
||||
horizontal: 16.0,
|
||||
vertical: 8.0,
|
||||
horizontal: 16,
|
||||
vertical: 8,
|
||||
),
|
||||
});
|
||||
|
||||
@@ -32,9 +32,9 @@ class UrlAttachment extends StatelessWidget {
|
||||
if (urlAttachment.imageUrl != null)
|
||||
Container(
|
||||
clipBehavior: Clip.antiAliasWithSaveLayer,
|
||||
margin: EdgeInsets.symmetric(horizontal: 8.0),
|
||||
margin: EdgeInsets.symmetric(horizontal: 8),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
@@ -44,20 +44,20 @@ class UrlAttachment extends StatelessWidget {
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
Positioned(
|
||||
left: 0.0,
|
||||
left: 0,
|
||||
bottom: -1,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.only(
|
||||
topRight: Radius.circular(16.0),
|
||||
topRight: Radius.circular(16),
|
||||
),
|
||||
color: StreamChatTheme.of(context).colorTheme.blueAlice,
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 8.0,
|
||||
left: 8.0,
|
||||
right: 8.0,
|
||||
top: 8,
|
||||
left: 8,
|
||||
right: 8,
|
||||
),
|
||||
child: Text(
|
||||
hostDisplayName,
|
||||
|
||||
@@ -42,7 +42,6 @@ class UserAvatar extends StatelessWidget {
|
||||
Widget avatar = FittedBox(
|
||||
fit: BoxFit.cover,
|
||||
child: ClipRRect(
|
||||
clipBehavior: Clip.antiAlias,
|
||||
borderRadius: borderRadius ??
|
||||
streamChatTheme.ownMessageTheme.avatarTheme?.borderRadius,
|
||||
child: Container(
|
||||
@@ -97,7 +96,7 @@ class UserAvatar extends StatelessWidget {
|
||||
type: MaterialType.circle,
|
||||
color: streamChatTheme.colorTheme.white,
|
||||
child: Container(
|
||||
margin: const EdgeInsets.all(2.0),
|
||||
margin: const EdgeInsets.all(2),
|
||||
constraints: onlineIndicatorConstraints ??
|
||||
BoxConstraints.tightFor(
|
||||
width: 8,
|
||||
|
||||
@@ -61,7 +61,6 @@ class UserItem extends StatelessWidget {
|
||||
},
|
||||
leading: UserAvatar(
|
||||
user: user,
|
||||
showOnlineStatus: true,
|
||||
onTap: (user) {
|
||||
if (onImageTap != null) {
|
||||
onImageTap!(user);
|
||||
|
||||
@@ -151,7 +151,7 @@ class _UserListViewState extends State<UserListView>
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var child = UserListCore(
|
||||
final child = UserListCore(
|
||||
errorBuilder: widget.errorBuilder as Widget Function(Object)? ??
|
||||
(err) {
|
||||
return _buildError(err as Error);
|
||||
@@ -225,7 +225,7 @@ class _UserListViewState extends State<UserListView>
|
||||
WidgetSpan(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
right: 2.0,
|
||||
right: 2,
|
||||
),
|
||||
child: Icon(Icons.error_outline),
|
||||
),
|
||||
@@ -237,7 +237,7 @@ class _UserListViewState extends State<UserListView>
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 16.0,
|
||||
top: 16,
|
||||
),
|
||||
child: Text(message),
|
||||
),
|
||||
@@ -313,7 +313,7 @@ class _UserListViewState extends State<UserListView>
|
||||
color:
|
||||
StreamChatTheme.of(context).colorTheme.black.withOpacity(0.05),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 6),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 6),
|
||||
child: Text(
|
||||
header,
|
||||
style: TextStyle(
|
||||
@@ -360,7 +360,6 @@ class _UserListViewState extends State<UserListView>
|
||||
? widget.userItemBuilder!(context, user, selected)
|
||||
: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
UserAvatar(
|
||||
user: user,
|
||||
@@ -414,7 +413,7 @@ class _UserListViewState extends State<UserListView>
|
||||
.accentRed
|
||||
.withOpacity(.2),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
child: Center(
|
||||
child: Text('Error loading users'),
|
||||
),
|
||||
|
||||
@@ -23,7 +23,7 @@ class UserReactionDisplay extends StatelessWidget {
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: reactionToEmoji.keys.map((reactionType) {
|
||||
var firstUserReaction = message.latestReactions!
|
||||
final firstUserReaction = message.latestReactions!
|
||||
.firstWhere((element) => element.type == reactionType,
|
||||
orElse: () {
|
||||
return null;
|
||||
|
||||
@@ -33,8 +33,8 @@ Future<bool?> showConfirmationDialog(
|
||||
context: context,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(16.0),
|
||||
topRight: Radius.circular(16.0),
|
||||
topLeft: Radius.circular(16),
|
||||
topRight: Radius.circular(16),
|
||||
)),
|
||||
builder: (context) {
|
||||
final effect = StreamChatTheme.of(context).colorTheme.borderTop;
|
||||
@@ -42,20 +42,20 @@ Future<bool?> showConfirmationDialog(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SizedBox(height: 26.0),
|
||||
SizedBox(height: 26),
|
||||
if (icon != null) icon,
|
||||
SizedBox(height: 26.0),
|
||||
SizedBox(height: 26),
|
||||
Text(
|
||||
title,
|
||||
style: StreamChatTheme.of(context).textTheme.headlineBold,
|
||||
),
|
||||
SizedBox(height: 7.0),
|
||||
SizedBox(height: 7),
|
||||
if (question != null)
|
||||
Text(
|
||||
question,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
SizedBox(height: 36.0),
|
||||
SizedBox(height: 36),
|
||||
Container(
|
||||
color: effect.color!.withOpacity(effect.alpha ?? 1),
|
||||
height: 1,
|
||||
@@ -126,8 +126,8 @@ Future<bool?> showInfoDialog(
|
||||
context: context,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(16.0),
|
||||
topRight: Radius.circular(16.0),
|
||||
topLeft: Radius.circular(16),
|
||||
topRight: Radius.circular(16),
|
||||
)),
|
||||
builder: (context) {
|
||||
return SafeArea(
|
||||
@@ -135,11 +135,11 @@ Future<bool?> showInfoDialog(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 26.0,
|
||||
height: 26,
|
||||
),
|
||||
if (icon != null) icon,
|
||||
SizedBox(
|
||||
height: 26.0,
|
||||
height: 26,
|
||||
),
|
||||
Text(
|
||||
title,
|
||||
@@ -147,16 +147,16 @@ Future<bool?> showInfoDialog(
|
||||
StreamChatTheme.of(context).textTheme.headlineBold,
|
||||
),
|
||||
SizedBox(
|
||||
height: 7.0,
|
||||
height: 7,
|
||||
),
|
||||
if (details != null) Text(details),
|
||||
SizedBox(
|
||||
height: 36.0,
|
||||
height: 36,
|
||||
),
|
||||
Container(
|
||||
color: theme?.colorTheme.black.withOpacity(.08) ??
|
||||
StreamChatTheme.of(context).colorTheme.black.withOpacity(.08),
|
||||
height: 1.0,
|
||||
height: 1,
|
||||
),
|
||||
Center(
|
||||
child: TextButton(
|
||||
@@ -236,7 +236,7 @@ String fileSize(dynamic size, [int round = 2]) {
|
||||
* the optional parameter [round] specifies the number
|
||||
* of digits after comma/point (default is 2)
|
||||
*/
|
||||
final divider = 1024;
|
||||
const divider = 1024;
|
||||
int _size;
|
||||
try {
|
||||
_size = int.parse(size.toString());
|
||||
@@ -274,21 +274,21 @@ String fileSize(dynamic size, [int round = 2]) {
|
||||
|
||||
if (_size < divider * divider * divider * divider * divider &&
|
||||
_size % divider == 0) {
|
||||
num r = _size / divider / divider / divider / divider;
|
||||
final num r = _size / divider / divider / divider / divider;
|
||||
return '${r.toStringAsFixed(0)} TB';
|
||||
}
|
||||
|
||||
if (_size < divider * divider * divider * divider * divider) {
|
||||
num r = _size / divider / divider / divider / divider;
|
||||
final num r = _size / divider / divider / divider / divider;
|
||||
return '${r.toStringAsFixed(round)} TB';
|
||||
}
|
||||
|
||||
if (_size < divider * divider * divider * divider * divider * divider &&
|
||||
_size % divider == 0) {
|
||||
num r = _size / divider / divider / divider / divider / divider;
|
||||
final num r = _size / divider / divider / divider / divider / divider;
|
||||
return '${r.toStringAsFixed(0)} PB';
|
||||
} else {
|
||||
num r = _size / divider / divider / divider / divider / divider;
|
||||
final num r = _size / divider / divider / divider / divider / divider;
|
||||
return '${r.toStringAsFixed(round)} PB';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,7 +239,7 @@ void main() {
|
||||
),
|
||||
);
|
||||
await tester.tap(find.text('Show in Chat'));
|
||||
verify(() => onShowMessage.call()).called(1);
|
||||
verify(onShowMessage.call).called(1);
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -26,8 +26,8 @@ void main() {
|
||||
child: Container(
|
||||
child: FileAttachment(
|
||||
size: Size(
|
||||
300.0,
|
||||
300.0,
|
||||
300,
|
||||
300,
|
||||
),
|
||||
message: Message(),
|
||||
attachment: Attachment(
|
||||
|
||||
@@ -318,7 +318,6 @@ void main() {
|
||||
body: ChannelHeader(
|
||||
showTypingIndicator: false,
|
||||
showBackButton: false,
|
||||
showConnectionStateTile: false,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -224,7 +224,6 @@ void main() {
|
||||
borderColor: Colors.red,
|
||||
backgroundColor: Colors.blue,
|
||||
maskColor: Colors.green,
|
||||
highlightOwnReactions: true,
|
||||
reverse: true,
|
||||
flipTail: true,
|
||||
tailCirclesSpacing: 4,
|
||||
|
||||
Reference in New Issue
Block a user