Merge branch 'feature/new-ui' of github.com:GetStream/stream-chat-flutter into feat/messg-reply
Conflicts: example/ios/Flutter/.last_build_id example/lib/main.dart lib/src/file_attachment.dart lib/src/message_actions_modal.dart lib/src/message_input.dart lib/src/message_widget.dart
This commit is contained in:
+61
-61
@@ -1,63 +1,63 @@
|
|||||||
include: package:pedantic/analysis_options.yaml
|
#include: package:pedantic/analysis_options.yaml
|
||||||
|
#
|
||||||
analyzer:
|
#analyzer:
|
||||||
enable-experiment:
|
# enable-experiment:
|
||||||
- extension-methods
|
# - extension-methods
|
||||||
exclude:
|
# exclude:
|
||||||
- lib/**/*.g.dart
|
# - lib/**/*.g.dart
|
||||||
- example/**
|
# - example/**
|
||||||
|
#
|
||||||
linter:
|
#linter:
|
||||||
rules:
|
# rules:
|
||||||
# these rules are documented on and in the same order as
|
# # these rules are documented on and in the same order as
|
||||||
# the Dart Lint rules page to make maintenance easier
|
# # the Dart Lint rules page to make maintenance easier
|
||||||
# https://github.com/dart-lang/linter/blob/master/example/all.yaml
|
# # https://github.com/dart-lang/linter/blob/master/example/all.yaml
|
||||||
# - always_declare_return_types
|
# # - always_declare_return_types
|
||||||
# - always_specify_types
|
# # - always_specify_types
|
||||||
# - annotate_overrides
|
# # - annotate_overrides
|
||||||
# - avoid_as
|
# # - avoid_as
|
||||||
- avoid_empty_else
|
# - avoid_empty_else
|
||||||
- avoid_init_to_null
|
# - avoid_init_to_null
|
||||||
- avoid_return_types_on_setters
|
# - avoid_return_types_on_setters
|
||||||
- avoid_web_libraries_in_flutter
|
# - avoid_web_libraries_in_flutter
|
||||||
- await_only_futures
|
# - await_only_futures
|
||||||
- camel_case_types
|
# - camel_case_types
|
||||||
- cancel_subscriptions
|
# - cancel_subscriptions
|
||||||
- close_sinks
|
# - close_sinks
|
||||||
# - comment_references # we do not presume as to what people want to reference in their dartdocs
|
# # - 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
|
# # - constant_identifier_names # https://github.com/dart-lang/linter/issues/204
|
||||||
- control_flow_in_finally
|
# - control_flow_in_finally
|
||||||
- empty_constructor_bodies
|
# - empty_constructor_bodies
|
||||||
- empty_statements
|
# - empty_statements
|
||||||
- hash_and_equals
|
# - hash_and_equals
|
||||||
- implementation_imports
|
# - implementation_imports
|
||||||
# - invariant_booleans
|
# # - invariant_booleans
|
||||||
# - iterable_contains_unrelated_type
|
# # - iterable_contains_unrelated_type
|
||||||
- library_names
|
# - library_names
|
||||||
# - library_prefixes
|
# # - library_prefixes
|
||||||
# - list_remove_unrelated_type
|
# # - list_remove_unrelated_type
|
||||||
# - literal_only_boolean_expressions
|
# # - literal_only_boolean_expressions
|
||||||
- non_constant_identifier_names
|
# - non_constant_identifier_names
|
||||||
# - one_member_abstracts
|
# # - one_member_abstracts
|
||||||
# - only_throw_errors
|
# # - only_throw_errors
|
||||||
# - overridden_fields
|
# # - overridden_fields
|
||||||
# - package_api_docs
|
## - package_api_docs
|
||||||
- package_names
|
# - package_names
|
||||||
- package_prefixed_library_names
|
# - package_prefixed_library_names
|
||||||
- prefer_is_not_empty
|
# - prefer_is_not_empty
|
||||||
# - prefer_mixin # https://github.com/dart-lang/language/issues/32
|
# # - prefer_mixin # https://github.com/dart-lang/language/issues/32
|
||||||
- public_member_api_docs
|
# - public_member_api_docs
|
||||||
- slash_for_doc_comments
|
# - slash_for_doc_comments
|
||||||
# - sort_constructors_first
|
# # - sort_constructors_first
|
||||||
# - sort_unnamed_constructors_first
|
# # - sort_unnamed_constructors_first
|
||||||
# - super_goes_last # no longer needed w/ Dart 2
|
# # - super_goes_last # no longer needed w/ Dart 2
|
||||||
- test_types_in_equals
|
# - test_types_in_equals
|
||||||
- throw_in_finally
|
# - throw_in_finally
|
||||||
# - type_annotate_public_apis # subset of always_specify_types
|
# # - type_annotate_public_apis # subset of always_specify_types
|
||||||
- type_init_formals
|
# - type_init_formals
|
||||||
# - unawaited_futures
|
# # - unawaited_futures
|
||||||
- unnecessary_brace_in_string_interps
|
# - unnecessary_brace_in_string_interps
|
||||||
- unnecessary_getters_setters
|
# - unnecessary_getters_setters
|
||||||
- unnecessary_statements
|
# - unnecessary_statements
|
||||||
- unrelated_type_equality_checks
|
- unrelated_type_equality_checks
|
||||||
- valid_regexps
|
- valid_regexps
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
c3e639ccf9b069e37a7d1345194e6b99
|
c770358a10272b4ee1cdc2eb432445f6
|
||||||
@@ -3,12 +3,12 @@ import 'dart:io';
|
|||||||
import 'package:example/stream_version.dart';
|
import 'package:example/stream_version.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
import 'choose_user_page.dart';
|
||||||
import 'main.dart';
|
import 'main.dart';
|
||||||
import 'notifications_service.dart';
|
import 'notifications_service.dart';
|
||||||
import 'choose_user_page.dart';
|
|
||||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
|
||||||
|
|
||||||
class AdvancedOptionsPage extends StatefulWidget {
|
class AdvancedOptionsPage extends StatefulWidget {
|
||||||
@override
|
@override
|
||||||
@@ -34,20 +34,23 @@ class _AdvancedOptionsPageState extends State<AdvancedOptionsPage> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow,
|
||||||
resizeToAvoidBottomPadding: false,
|
resizeToAvoidBottomPadding: false,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
backgroundColor: StreamChatTheme.of(context).primaryColor,
|
backgroundColor: StreamChatTheme.of(context).colorTheme.white,
|
||||||
elevation: 1,
|
elevation: 1,
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
|
brightness: Theme.of(context).brightness,
|
||||||
title: Text(
|
title: Text(
|
||||||
'Advanced Options',
|
'Advanced Options',
|
||||||
style: Theme.of(context).textTheme.subtitle1.copyWith(
|
style: StreamChatTheme.of(context)
|
||||||
fontWeight: FontWeight.bold,
|
.textTheme
|
||||||
),
|
.headlineBold
|
||||||
|
.copyWith(color: StreamChatTheme.of(context).colorTheme.black),
|
||||||
),
|
),
|
||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
icon: StreamSvgIcon.left(
|
icon: StreamSvgIcon.left(
|
||||||
color: Colors.black,
|
color: StreamChatTheme.of(context).colorTheme.black,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
@@ -87,7 +90,7 @@ class _AdvancedOptionsPageState extends State<AdvancedOptionsPage> {
|
|||||||
},
|
},
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: Colors.black,
|
color: StreamChatTheme.of(context).colorTheme.black,
|
||||||
),
|
),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
errorStyle: TextStyle(fontSize: 0),
|
errorStyle: TextStyle(fontSize: 0),
|
||||||
@@ -95,14 +98,18 @@ class _AdvancedOptionsPageState extends State<AdvancedOptionsPage> {
|
|||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: _apiKeyError != null
|
color: _apiKeyError != null
|
||||||
? Color(0xffff3742)
|
? StreamChatTheme.of(context).colorTheme.accentRed
|
||||||
: Colors.black.withOpacity(.5),
|
: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(.5),
|
||||||
),
|
),
|
||||||
border: UnderlineInputBorder(
|
border: UnderlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
borderSide: BorderSide.none,
|
borderSide: BorderSide.none,
|
||||||
),
|
),
|
||||||
fillColor: Color(0xffF5F5F5),
|
fillColor:
|
||||||
|
StreamChatTheme.of(context).colorTheme.whiteSmoke,
|
||||||
filled: true,
|
filled: true,
|
||||||
labelText:
|
labelText:
|
||||||
'Chat API Key ${_apiKeyError != null ? ':$_apiKeyError' : ''}',
|
'Chat API Key ${_apiKeyError != null ? ':$_apiKeyError' : ''}',
|
||||||
@@ -131,7 +138,7 @@ class _AdvancedOptionsPageState extends State<AdvancedOptionsPage> {
|
|||||||
},
|
},
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: Colors.black,
|
color: StreamChatTheme.of(context).colorTheme.black,
|
||||||
),
|
),
|
||||||
textInputAction: TextInputAction.next,
|
textInputAction: TextInputAction.next,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
@@ -140,14 +147,18 @@ class _AdvancedOptionsPageState extends State<AdvancedOptionsPage> {
|
|||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: _userIdError != null
|
color: _userIdError != null
|
||||||
? Color(0xffff3742)
|
? StreamChatTheme.of(context).colorTheme.accentRed
|
||||||
: Colors.black.withOpacity(.5),
|
: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(.5),
|
||||||
),
|
),
|
||||||
border: UnderlineInputBorder(
|
border: UnderlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
borderSide: BorderSide.none,
|
borderSide: BorderSide.none,
|
||||||
),
|
),
|
||||||
fillColor: Color(0xffF5F5F5),
|
fillColor:
|
||||||
|
StreamChatTheme.of(context).colorTheme.whiteSmoke,
|
||||||
filled: true,
|
filled: true,
|
||||||
labelText:
|
labelText:
|
||||||
'User ID ${_userIdError != null ? ':$_userIdError' : ''}',
|
'User ID ${_userIdError != null ? ':$_userIdError' : ''}',
|
||||||
@@ -176,7 +187,7 @@ class _AdvancedOptionsPageState extends State<AdvancedOptionsPage> {
|
|||||||
},
|
},
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: Colors.black,
|
color: StreamChatTheme.of(context).colorTheme.black,
|
||||||
),
|
),
|
||||||
textInputAction: TextInputAction.next,
|
textInputAction: TextInputAction.next,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
@@ -185,14 +196,18 @@ class _AdvancedOptionsPageState extends State<AdvancedOptionsPage> {
|
|||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: _userTokenError != null
|
color: _userTokenError != null
|
||||||
? Color(0xffff3742)
|
? StreamChatTheme.of(context).colorTheme.accentRed
|
||||||
: Colors.black.withOpacity(.5),
|
: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(.5),
|
||||||
),
|
),
|
||||||
border: UnderlineInputBorder(
|
border: UnderlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
borderSide: BorderSide.none,
|
borderSide: BorderSide.none,
|
||||||
),
|
),
|
||||||
fillColor: Color(0xffF5F5F5),
|
fillColor:
|
||||||
|
StreamChatTheme.of(context).colorTheme.whiteSmoke,
|
||||||
filled: true,
|
filled: true,
|
||||||
labelText:
|
labelText:
|
||||||
'User Token ${_userTokenError != null ? ':$_userTokenError' : ''}',
|
'User Token ${_userTokenError != null ? ':$_userTokenError' : ''}',
|
||||||
@@ -208,13 +223,17 @@ class _AdvancedOptionsPageState extends State<AdvancedOptionsPage> {
|
|||||||
labelStyle: TextStyle(
|
labelStyle: TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: Colors.black.withOpacity(.5),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(.5),
|
||||||
),
|
),
|
||||||
border: UnderlineInputBorder(
|
border: UnderlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
borderSide: BorderSide.none,
|
borderSide: BorderSide.none,
|
||||||
),
|
),
|
||||||
fillColor: Color(0xffF5F5F5),
|
fillColor:
|
||||||
|
StreamChatTheme.of(context).colorTheme.whiteSmoke,
|
||||||
filled: true,
|
filled: true,
|
||||||
labelText: 'Username (optional)',
|
labelText: 'Username (optional)',
|
||||||
),
|
),
|
||||||
@@ -224,13 +243,14 @@ class _AdvancedOptionsPageState extends State<AdvancedOptionsPage> {
|
|||||||
child: Align(
|
child: Align(
|
||||||
alignment: Alignment.bottomCenter,
|
alignment: Alignment.bottomCenter,
|
||||||
child: FlatButton(
|
child: FlatButton(
|
||||||
color: StreamChatTheme.of(context).accentColor,
|
color:
|
||||||
|
StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||||
minWidth: double.infinity,
|
minWidth: double.infinity,
|
||||||
height: 48,
|
height: 48,
|
||||||
child: Text(
|
child: Text(
|
||||||
'Login',
|
'Login',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -255,7 +275,9 @@ class _AdvancedOptionsPageState extends State<AdvancedOptionsPage> {
|
|||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius: BorderRadius.circular(16),
|
||||||
color: Colors.white,
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.white,
|
||||||
),
|
),
|
||||||
height: 100,
|
height: 100,
|
||||||
width: 100,
|
width: 100,
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ class ChipInputTextFieldState<T> extends State<ChipsInputTextField<T>> {
|
|||||||
onTap: _pauseItemAddition ? resumeItemAddition : null,
|
onTap: _pauseItemAddition ? resumeItemAddition : null,
|
||||||
child: Material(
|
child: Material(
|
||||||
elevation: 1,
|
elevation: 1,
|
||||||
color: Colors.white,
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
child: Container(
|
child: Container(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(16, 16, 16, 16),
|
padding: const EdgeInsets.fromLTRB(16, 16, 16, 16),
|
||||||
@@ -78,10 +78,14 @@ class ChipInputTextFieldState<T> extends State<ChipsInputTextField<T>> {
|
|||||||
padding: const EdgeInsets.symmetric(vertical: 4.0),
|
padding: const EdgeInsets.symmetric(vertical: 4.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
'TO:',
|
'TO:',
|
||||||
style: TextStyle(
|
style: StreamChatTheme.of(context)
|
||||||
fontSize: 12,
|
.textTheme
|
||||||
color: Colors.black.withOpacity(0.5),
|
.footnote
|
||||||
),
|
.copyWith(
|
||||||
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(.5)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(width: 12),
|
SizedBox(width: 12),
|
||||||
@@ -111,10 +115,14 @@ class ChipInputTextFieldState<T> extends State<ChipsInputTextField<T>> {
|
|||||||
disabledBorder: InputBorder.none,
|
disabledBorder: InputBorder.none,
|
||||||
contentPadding: const EdgeInsets.only(top: 4.0),
|
contentPadding: const EdgeInsets.only(top: 4.0),
|
||||||
hintText: widget.hint,
|
hintText: widget.hint,
|
||||||
hintStyle: TextStyle(
|
hintStyle: StreamChatTheme.of(context)
|
||||||
color: Colors.black.withOpacity(0.5),
|
.textTheme
|
||||||
fontSize: 14,
|
.body
|
||||||
),
|
.copyWith(
|
||||||
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(.5)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -126,11 +134,17 @@ class ChipInputTextFieldState<T> extends State<ChipsInputTextField<T>> {
|
|||||||
child: IconButton(
|
child: IconButton(
|
||||||
icon: _chips.isEmpty
|
icon: _chips.isEmpty
|
||||||
? StreamSvgIcon.user(
|
? StreamSvgIcon.user(
|
||||||
color: Colors.black.withOpacity(0.5),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(0.5),
|
||||||
size: 24,
|
size: 24,
|
||||||
)
|
)
|
||||||
: StreamSvgIcon.userAdd(
|
: StreamSvgIcon.userAdd(
|
||||||
color: Colors.black.withOpacity(0.5),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(0.5),
|
||||||
size: 24,
|
size: 24,
|
||||||
),
|
),
|
||||||
onPressed: resumeItemAddition,
|
onPressed: resumeItemAddition,
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import 'package:example/advanced_options_page.dart';
|
|
||||||
import 'package:example/main.dart';
|
|
||||||
import 'package:example/stream_version.dart';
|
import 'package:example/stream_version.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@@ -60,6 +58,7 @@ class ChooseUserPage extends StatelessWidget {
|
|||||||
(_, value) => value..extraData['image'] = getRandomPicUrl(value));
|
(_, value) => value..extraData['image'] = getRandomPicUrl(value));
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow,
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
@@ -80,19 +79,12 @@ class ChooseUserPage extends StatelessWidget {
|
|||||||
padding: const EdgeInsets.only(bottom: 13.0),
|
padding: const EdgeInsets.only(bottom: 13.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
'Welcome to Stream Chat',
|
'Welcome to Stream Chat',
|
||||||
style: TextStyle(
|
style: StreamChatTheme.of(context).textTheme.title,
|
||||||
fontSize: 22,
|
|
||||||
color: Colors.black,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'Select a user to try the Flutter SDK:',
|
'Select a user to try the Flutter SDK:',
|
||||||
style: TextStyle(
|
style: StreamChatTheme.of(context).textTheme.body,
|
||||||
fontSize: 14.5,
|
|
||||||
color: Colors.black,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
@@ -120,7 +112,9 @@ class ChooseUserPage extends StatelessWidget {
|
|||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius: BorderRadius.circular(16),
|
||||||
color: Colors.white,
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.white,
|
||||||
),
|
),
|
||||||
height: 100,
|
height: 100,
|
||||||
width: 100,
|
width: 100,
|
||||||
@@ -169,9 +163,20 @@ class ChooseUserPage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
user.name,
|
user.name,
|
||||||
style: TextStyle(fontWeight: FontWeight.bold),
|
style:
|
||||||
|
StreamChatTheme.of(context).textTheme.bodyBold,
|
||||||
|
),
|
||||||
|
subtitle: Text(
|
||||||
|
'Stream test account',
|
||||||
|
style: StreamChatTheme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.footnote
|
||||||
|
.copyWith(
|
||||||
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.grey,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
subtitle: Text('Stream test account'),
|
|
||||||
trailing: SvgPicture.asset(
|
trailing: SvgPicture.asset(
|
||||||
'assets/icon_arrow_right.svg',
|
'assets/icon_arrow_right.svg',
|
||||||
height: 24,
|
height: 24,
|
||||||
@@ -185,16 +190,26 @@ class ChooseUserPage extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
leading: CircleAvatar(
|
leading: CircleAvatar(
|
||||||
child: StreamSvgIcon.settings(
|
child: StreamSvgIcon.settings(
|
||||||
color: Colors.black,
|
color: StreamChatTheme.of(context).colorTheme.black,
|
||||||
),
|
),
|
||||||
backgroundColor:
|
backgroundColor: StreamChatTheme.of(context)
|
||||||
StreamChatTheme.of(context).secondaryColor,
|
.colorTheme
|
||||||
|
.greyWhisper,
|
||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
'Advanced Options',
|
'Advanced Options',
|
||||||
style: TextStyle(fontWeight: FontWeight.bold),
|
style: StreamChatTheme.of(context).textTheme.bodyBold,
|
||||||
|
),
|
||||||
|
subtitle: Text(
|
||||||
|
'Custom settings',
|
||||||
|
style: StreamChatTheme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.footnote
|
||||||
|
.copyWith(
|
||||||
|
color:
|
||||||
|
StreamChatTheme.of(context).colorTheme.grey,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
subtitle: Text('Custom settings'),
|
|
||||||
trailing: SvgPicture.asset(
|
trailing: SvgPicture.asset(
|
||||||
'assets/icon_arrow_right.svg',
|
'assets/icon_arrow_right.svg',
|
||||||
height: 24,
|
height: 24,
|
||||||
|
|||||||
@@ -50,9 +50,10 @@ class MyApp extends StatelessWidget {
|
|||||||
client: client,
|
client: client,
|
||||||
streamChatThemeData: StreamChatThemeData.fromTheme(theme).copyWith(
|
streamChatThemeData: StreamChatThemeData.fromTheme(theme).copyWith(
|
||||||
ownMessageTheme: MessageTheme(
|
ownMessageTheme: MessageTheme(
|
||||||
messageBackgroundColor: Colors.black,
|
messageBackgroundColor:
|
||||||
|
StreamChatTheme.of(context).colorTheme.black,
|
||||||
messageText: TextStyle(
|
messageText: TextStyle(
|
||||||
color: Colors.white,
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
),
|
),
|
||||||
avatarTheme: AvatarTheme(
|
avatarTheme: AvatarTheme(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
|||||||
@@ -84,10 +84,12 @@ class ChannelListPage extends StatelessWidget {
|
|||||||
channel: channel,
|
channel: channel,
|
||||||
),
|
),
|
||||||
title: ChannelName(
|
title: ChannelName(
|
||||||
channel: channel,
|
|
||||||
textStyle:
|
textStyle:
|
||||||
StreamChatTheme.of(context).channelPreviewTheme.title.copyWith(
|
StreamChatTheme.of(context).channelPreviewTheme.title.copyWith(
|
||||||
color: Colors.black.withOpacity(opacity),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(opacity),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
subtitle: Text(subtitle),
|
subtitle: Text(subtitle),
|
||||||
|
|||||||
@@ -127,7 +127,6 @@ class ChannelPage extends StatelessWidget {
|
|||||||
showTimestamp: !details.isNextUser,
|
showTimestamp: !details.isNextUser,
|
||||||
showUsername: !details.isNextUser,
|
showUsername: !details.isNextUser,
|
||||||
showReactions: false,
|
showReactions: false,
|
||||||
showReplyIndicator: false,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,15 +59,16 @@ class _GroupChatDetailsScreenState extends State<GroupChatDetailsScreen> {
|
|||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
backgroundColor: Color.fromRGBO(252, 252, 252, 1),
|
backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
|
brightness: Theme.of(context).brightness,
|
||||||
elevation: 1,
|
elevation: 1,
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: StreamChatTheme.of(context).colorTheme.white,
|
||||||
leading: const StreamBackButton(),
|
leading: const StreamBackButton(),
|
||||||
title: Text(
|
title: Text(
|
||||||
'Name of Group Chat',
|
'Name of Group Chat',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.black,
|
color: StreamChatTheme.of(context).colorTheme.black,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -82,7 +83,10 @@ class _GroupChatDetailsScreenState extends State<GroupChatDetailsScreen> {
|
|||||||
'NAME',
|
'NAME',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
color: Colors.black.withOpacity(0.5),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(0.5),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(width: 16),
|
SizedBox(width: 16),
|
||||||
@@ -99,7 +103,11 @@ class _GroupChatDetailsScreenState extends State<GroupChatDetailsScreen> {
|
|||||||
contentPadding: const EdgeInsets.all(0),
|
contentPadding: const EdgeInsets.all(0),
|
||||||
hintText: 'Choose a group chat name',
|
hintText: 'Choose a group chat name',
|
||||||
hintStyle: TextStyle(
|
hintStyle: TextStyle(
|
||||||
fontSize: 14, color: Colors.black.withOpacity(.5)),
|
fontSize: 14,
|
||||||
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(.5)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -113,7 +121,9 @@ class _GroupChatDetailsScreenState extends State<GroupChatDetailsScreen> {
|
|||||||
padding: const EdgeInsets.all(0),
|
padding: const EdgeInsets.all(0),
|
||||||
icon: StreamSvgIcon.check(
|
icon: StreamSvgIcon.check(
|
||||||
size: 24,
|
size: 24,
|
||||||
color: _isGroupNameEmpty ? Colors.grey : Color(0xFF006CFF),
|
color: _isGroupNameEmpty
|
||||||
|
? Colors.grey
|
||||||
|
: StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||||
),
|
),
|
||||||
onPressed: _isGroupNameEmpty
|
onPressed: _isGroupNameEmpty
|
||||||
? null
|
? null
|
||||||
@@ -144,7 +154,16 @@ class _GroupChatDetailsScreenState extends State<GroupChatDetailsScreen> {
|
|||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
width: double.maxFinite,
|
width: double.maxFinite,
|
||||||
color: Colors.grey.shade50,
|
decoration: BoxDecoration(
|
||||||
|
gradient: LinearGradient(
|
||||||
|
begin: Alignment.topCenter,
|
||||||
|
end: Alignment.bottomCenter,
|
||||||
|
colors: [
|
||||||
|
StreamChatTheme.of(context).colorTheme.whiteSmoke,
|
||||||
|
StreamChatTheme.of(context).colorTheme.whiteSnow,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
vertical: 8,
|
vertical: 8,
|
||||||
@@ -167,16 +186,28 @@ class _GroupChatDetailsScreenState extends State<GroupChatDetailsScreen> {
|
|||||||
separatorBuilder: (_, __) => Container(
|
separatorBuilder: (_, __) => Container(
|
||||||
height: 1,
|
height: 1,
|
||||||
color: Theme.of(context).brightness == Brightness.dark
|
color: Theme.of(context).brightness == Brightness.dark
|
||||||
? Colors.white.withOpacity(0.1)
|
? StreamChatTheme.of(context)
|
||||||
: Colors.black.withOpacity(0.1),
|
.colorTheme
|
||||||
|
.white
|
||||||
|
.withOpacity(0.1)
|
||||||
|
: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(0.1),
|
||||||
),
|
),
|
||||||
itemBuilder: (_, index) {
|
itemBuilder: (_, index) {
|
||||||
if (index == _selectedUsers.length) {
|
if (index == _selectedUsers.length) {
|
||||||
return Container(
|
return Container(
|
||||||
height: 1,
|
height: 1,
|
||||||
color: Theme.of(context).brightness == Brightness.dark
|
color: Theme.of(context).brightness == Brightness.dark
|
||||||
? Colors.white.withOpacity(0.1)
|
? StreamChatTheme.of(context)
|
||||||
: Colors.black.withOpacity(0.1),
|
.colorTheme
|
||||||
|
.white
|
||||||
|
.withOpacity(0.1)
|
||||||
|
: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(0.1),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
final user = _selectedUsers[index];
|
final user = _selectedUsers[index];
|
||||||
@@ -200,7 +231,7 @@ class _GroupChatDetailsScreenState extends State<GroupChatDetailsScreen> {
|
|||||||
trailing: IconButton(
|
trailing: IconButton(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
Icons.clear_rounded,
|
Icons.clear_rounded,
|
||||||
color: Colors.black,
|
color: StreamChatTheme.of(context).colorTheme.black,
|
||||||
),
|
),
|
||||||
padding: const EdgeInsets.all(0),
|
padding: const EdgeInsets.all(0),
|
||||||
splashRadius: 24,
|
splashRadius: 24,
|
||||||
|
|||||||
+136
-112
@@ -1,8 +1,7 @@
|
|||||||
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:example/choose_user_page.dart';
|
import 'package:example/choose_user_page.dart';
|
||||||
import 'package:example/new_chat_screen.dart';
|
|
||||||
import 'package:example/new_group_chat_screen.dart';
|
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@@ -13,7 +12,6 @@ import 'notifications_service.dart';
|
|||||||
import 'routes/app_routes.dart';
|
import 'routes/app_routes.dart';
|
||||||
import 'routes/routes.dart';
|
import 'routes/routes.dart';
|
||||||
import 'search_text_field.dart';
|
import 'search_text_field.dart';
|
||||||
import 'dart:async';
|
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
@@ -28,7 +26,7 @@ void main() async {
|
|||||||
logLevel: Level.INFO,
|
logLevel: Level.INFO,
|
||||||
showLocalNotification:
|
showLocalNotification:
|
||||||
(!kIsWeb && Platform.isAndroid) ? showLocalNotification : null,
|
(!kIsWeb && Platform.isAndroid) ? showLocalNotification : null,
|
||||||
persistenceEnabled: true,
|
persistenceEnabled: false,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (userId != null) {
|
if (userId != null) {
|
||||||
@@ -52,18 +50,20 @@ class MyApp extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return StreamChat(
|
return MaterialApp(
|
||||||
client: client,
|
builder: (context, child) {
|
||||||
child: MaterialApp(
|
return StreamChat(
|
||||||
debugShowCheckedModeBanner: false,
|
client: client,
|
||||||
theme: ThemeData.light(),
|
child: child,
|
||||||
darkTheme: ThemeData.dark(),
|
);
|
||||||
//TODO change to system once dark theme is implemented
|
},
|
||||||
themeMode: ThemeMode.light,
|
debugShowCheckedModeBanner: false,
|
||||||
onGenerateRoute: AppRoutes.generateRoute,
|
theme: ThemeData.light(),
|
||||||
initialRoute:
|
darkTheme: ThemeData.dark(),
|
||||||
client.state.user == null ? Routes.CHOOSE_USER : Routes.HOME,
|
themeMode: ThemeMode.dark,
|
||||||
),
|
onGenerateRoute: AppRoutes.generateRoute,
|
||||||
|
initialRoute:
|
||||||
|
client.state.user == null ? Routes.CHOOSE_USER : Routes.HOME,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -85,7 +85,9 @@ class _HomePageState extends State<HomePage> {
|
|||||||
overflow: Overflow.visible,
|
overflow: Overflow.visible,
|
||||||
children: [
|
children: [
|
||||||
StreamSvgIcon.message(
|
StreamSvgIcon.message(
|
||||||
color: _isSelected(0) ? Colors.black : Colors.grey,
|
color: _isSelected(0)
|
||||||
|
? StreamChatTheme.of(context).colorTheme.black
|
||||||
|
: Colors.grey,
|
||||||
),
|
),
|
||||||
Positioned(
|
Positioned(
|
||||||
top: -3,
|
top: -3,
|
||||||
@@ -101,7 +103,9 @@ class _HomePageState extends State<HomePage> {
|
|||||||
overflow: Overflow.visible,
|
overflow: Overflow.visible,
|
||||||
children: [
|
children: [
|
||||||
StreamSvgIcon.mentions(
|
StreamSvgIcon.mentions(
|
||||||
color: _isSelected(1) ? Colors.black : Colors.grey,
|
color: _isSelected(1)
|
||||||
|
? StreamChatTheme.of(context).colorTheme.black
|
||||||
|
: Colors.grey,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -114,6 +118,7 @@ class _HomePageState extends State<HomePage> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final user = StreamChat.of(context).user;
|
final user = StreamChat.of(context).user;
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow,
|
||||||
appBar: ChannelListHeader(
|
appBar: ChannelListHeader(
|
||||||
onNewChatButtonTap: () {
|
onNewChatButtonTap: () {
|
||||||
Navigator.pushNamed(context, Routes.NEW_CHAT);
|
Navigator.pushNamed(context, Routes.NEW_CHAT);
|
||||||
@@ -122,10 +127,14 @@ class _HomePageState extends State<HomePage> {
|
|||||||
drawer: _buildDrawer(context, user),
|
drawer: _buildDrawer(context, user),
|
||||||
drawerEdgeDragWidth: 50,
|
drawerEdgeDragWidth: 50,
|
||||||
bottomNavigationBar: BottomNavigationBar(
|
bottomNavigationBar: BottomNavigationBar(
|
||||||
|
backgroundColor: StreamChatTheme.of(context).colorTheme.white,
|
||||||
currentIndex: _currentIndex,
|
currentIndex: _currentIndex,
|
||||||
items: _navBarItems,
|
items: _navBarItems,
|
||||||
|
selectedLabelStyle: StreamChatTheme.of(context).textTheme.footnoteBold,
|
||||||
|
unselectedLabelStyle:
|
||||||
|
StreamChatTheme.of(context).textTheme.footnoteBold,
|
||||||
type: BottomNavigationBarType.fixed,
|
type: BottomNavigationBarType.fixed,
|
||||||
selectedItemColor: Colors.black,
|
selectedItemColor: StreamChatTheme.of(context).colorTheme.black,
|
||||||
unselectedItemColor: Colors.grey,
|
unselectedItemColor: Colors.grey,
|
||||||
onTap: (index) {
|
onTap: (index) {
|
||||||
setState(() => _currentIndex = index);
|
setState(() => _currentIndex = index);
|
||||||
@@ -143,104 +152,116 @@ class _HomePageState extends State<HomePage> {
|
|||||||
|
|
||||||
Drawer _buildDrawer(BuildContext context, User user) {
|
Drawer _buildDrawer(BuildContext context, User user) {
|
||||||
return Drawer(
|
return Drawer(
|
||||||
child: SafeArea(
|
child: Container(
|
||||||
child: Padding(
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
padding: EdgeInsets.only(
|
child: SafeArea(
|
||||||
top: MediaQuery.of(context).viewPadding.top + 8,
|
child: Padding(
|
||||||
),
|
padding: EdgeInsets.only(
|
||||||
child: Column(
|
top: MediaQuery.of(context).viewPadding.top + 8,
|
||||||
children: [
|
),
|
||||||
Padding(
|
child: Column(
|
||||||
padding: const EdgeInsets.only(
|
children: [
|
||||||
bottom: 20.0,
|
Padding(
|
||||||
left: 8,
|
padding: const EdgeInsets.only(
|
||||||
|
bottom: 20.0,
|
||||||
|
left: 8,
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
UserAvatar(
|
||||||
|
user: user,
|
||||||
|
showOnlineStatus: false,
|
||||||
|
constraints: BoxConstraints.tight(Size.fromRadius(20)),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 16.0),
|
||||||
|
child: Text(
|
||||||
|
user.name,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
child: Row(
|
ListTile(
|
||||||
children: [
|
leading: StreamSvgIcon.penWrite(
|
||||||
UserAvatar(
|
color: StreamChatTheme.of(context)
|
||||||
user: user,
|
.colorTheme
|
||||||
showOnlineStatus: false,
|
.black
|
||||||
constraints: BoxConstraints.tight(Size.fromRadius(20)),
|
.withOpacity(.5),
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
|
Navigator.popAndPushNamed(
|
||||||
|
context,
|
||||||
|
Routes.NEW_CHAT,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
title: Text(
|
||||||
|
'New direct message',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14.5,
|
||||||
),
|
),
|
||||||
Padding(
|
),
|
||||||
padding: const EdgeInsets.only(left: 16.0),
|
),
|
||||||
child: Text(
|
ListTile(
|
||||||
user.name,
|
leading: StreamSvgIcon.contacts(
|
||||||
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(.5),
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
|
Navigator.popAndPushNamed(
|
||||||
|
context,
|
||||||
|
Routes.NEW_GROUP_CHAT,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
title: Text(
|
||||||
|
'New group',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14.5,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Container(
|
||||||
|
alignment: Alignment.bottomCenter,
|
||||||
|
child: ListTile(
|
||||||
|
onTap: () async {
|
||||||
|
Navigator.pop(context);
|
||||||
|
|
||||||
|
final secureStorage = FlutterSecureStorage();
|
||||||
|
await secureStorage.deleteAll();
|
||||||
|
|
||||||
|
StreamChat.of(context).client.disconnect(
|
||||||
|
clearUser: true,
|
||||||
|
);
|
||||||
|
|
||||||
|
await Navigator.pushReplacementNamed(
|
||||||
|
context,
|
||||||
|
Routes.CHOOSE_USER,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
leading: StreamSvgIcon.user(
|
||||||
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(.5),
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
'Sign out',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 14.5,
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
ListTile(
|
|
||||||
leading: StreamSvgIcon.penWrite(
|
|
||||||
color: Colors.black.withOpacity(.5),
|
|
||||||
),
|
|
||||||
onTap: () {
|
|
||||||
Navigator.popAndPushNamed(
|
|
||||||
context,
|
|
||||||
Routes.NEW_CHAT,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
title: Text(
|
|
||||||
'New direct message',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 14.5,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
ListTile(
|
),
|
||||||
leading: StreamSvgIcon.contacts(
|
|
||||||
color: Colors.black.withOpacity(.5),
|
|
||||||
),
|
|
||||||
onTap: () {
|
|
||||||
Navigator.popAndPushNamed(
|
|
||||||
context,
|
|
||||||
Routes.NEW_GROUP_CHAT,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
title: Text(
|
|
||||||
'New group',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 14.5,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: Container(
|
|
||||||
alignment: Alignment.bottomCenter,
|
|
||||||
child: ListTile(
|
|
||||||
onTap: () async {
|
|
||||||
Navigator.pop(context);
|
|
||||||
|
|
||||||
final secureStorage = FlutterSecureStorage();
|
|
||||||
await secureStorage.deleteAll();
|
|
||||||
|
|
||||||
StreamChat.of(context).client.disconnect(
|
|
||||||
clearUser: true,
|
|
||||||
);
|
|
||||||
|
|
||||||
await Navigator.pushReplacementNamed(
|
|
||||||
context,
|
|
||||||
Routes.CHOOSE_USER,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
leading: StreamSvgIcon.user(
|
|
||||||
color: Colors.black.withOpacity(.5),
|
|
||||||
),
|
|
||||||
title: Text(
|
|
||||||
'Sign out',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 14.5,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -436,7 +457,7 @@ class _ChannelPageState extends State<ChannelPage> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: Color.fromRGBO(252, 252, 252, 1),
|
backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow,
|
||||||
appBar: ChannelHeader(
|
appBar: ChannelHeader(
|
||||||
showTypingIndicator: false,
|
showTypingIndicator: false,
|
||||||
),
|
),
|
||||||
@@ -463,7 +484,10 @@ class _ChannelPageState extends State<ChannelPage> {
|
|||||||
right: 0,
|
right: 0,
|
||||||
child: Container(
|
child: Container(
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
color: Color(0xffFCFCFC).withOpacity(.9),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.whiteSnow
|
||||||
|
.withOpacity(.9),
|
||||||
child: TypingIndicator(
|
child: TypingIndicator(
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
@@ -501,7 +525,7 @@ class ThreadPage extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: Color.fromRGBO(252, 252, 252, 1),
|
backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow,
|
||||||
appBar: ThreadHeader(
|
appBar: ThreadHeader(
|
||||||
parent: parent,
|
parent: parent,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
|||||||
|
|
||||||
import 'chips_input_text_field.dart';
|
import 'chips_input_text_field.dart';
|
||||||
import 'main.dart';
|
import 'main.dart';
|
||||||
import 'new_group_chat_screen.dart';
|
|
||||||
import 'routes/routes.dart';
|
import 'routes/routes.dart';
|
||||||
|
|
||||||
class NewChatScreen extends StatefulWidget {
|
class NewChatScreen extends StatefulWidget {
|
||||||
@@ -37,8 +36,6 @@ class _NewChatScreenState extends State<NewChatScreen> {
|
|||||||
|
|
||||||
bool _showUserList = true;
|
bool _showUserList = true;
|
||||||
|
|
||||||
bool _channelExisted = false;
|
|
||||||
|
|
||||||
void _userNameListener() {
|
void _userNameListener() {
|
||||||
if (_debounce?.isActive ?? false) _debounce.cancel();
|
if (_debounce?.isActive ?? false) _debounce.cancel();
|
||||||
_debounce = Timer(const Duration(milliseconds: 350), () {
|
_debounce = Timer(const Duration(milliseconds: 350), () {
|
||||||
@@ -122,17 +119,18 @@ class _NewChatScreenState extends State<NewChatScreen> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: Color.fromRGBO(252, 252, 252, 1),
|
backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
|
brightness: Theme.of(context).brightness,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: StreamChatTheme.of(context).colorTheme.white,
|
||||||
leading: const StreamBackButton(),
|
leading: const StreamBackButton(),
|
||||||
title: Text(
|
title: Text(
|
||||||
'New Chat',
|
'New Chat',
|
||||||
style: TextStyle(
|
style: StreamChatTheme.of(context)
|
||||||
color: Colors.black,
|
.textTheme
|
||||||
fontSize: 16,
|
.headlineBold
|
||||||
),
|
.copyWith(color: StreamChatTheme.of(context).colorTheme.black),
|
||||||
),
|
),
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
),
|
),
|
||||||
@@ -157,7 +155,10 @@ class _NewChatScreenState extends State<NewChatScreen> {
|
|||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.black.withOpacity(0.05),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(0.05),
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
padding: const EdgeInsets.only(left: 24),
|
padding: const EdgeInsets.only(left: 24),
|
||||||
@@ -165,7 +166,10 @@ class _NewChatScreenState extends State<NewChatScreen> {
|
|||||||
padding: const EdgeInsets.fromLTRB(8, 4, 12, 4),
|
padding: const EdgeInsets.fromLTRB(8, 4, 12, 4),
|
||||||
child: Text(
|
child: Text(
|
||||||
user.name,
|
user.name,
|
||||||
style: TextStyle(color: Colors.black),
|
style: TextStyle(
|
||||||
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -182,7 +186,7 @@ class _NewChatScreenState extends State<NewChatScreen> {
|
|||||||
),
|
),
|
||||||
Positioned(
|
Positioned(
|
||||||
child: StreamSvgIcon.close(
|
child: StreamSvgIcon.close(
|
||||||
color: Colors.white,
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -212,7 +216,9 @@ class _NewChatScreenState extends State<NewChatScreen> {
|
|||||||
StreamNeumorphicButton(
|
StreamNeumorphicButton(
|
||||||
child: Center(
|
child: Center(
|
||||||
child: StreamSvgIcon.contacts(
|
child: StreamSvgIcon.contacts(
|
||||||
color: Color(0xFF006CFF),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.accentBlue,
|
||||||
size: 24,
|
size: 24,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -220,10 +226,7 @@ class _NewChatScreenState extends State<NewChatScreen> {
|
|||||||
SizedBox(width: 8),
|
SizedBox(width: 8),
|
||||||
Text(
|
Text(
|
||||||
'Create a Group',
|
'Create a Group',
|
||||||
style: TextStyle(
|
style: StreamChatTheme.of(context).textTheme.bodyBold,
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
fontSize: 16,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -238,8 +241,14 @@ class _NewChatScreenState extends State<NewChatScreen> {
|
|||||||
begin: Alignment.centerLeft,
|
begin: Alignment.centerLeft,
|
||||||
end: Alignment.centerRight,
|
end: Alignment.centerRight,
|
||||||
colors: [
|
colors: [
|
||||||
Colors.black.withOpacity(0.02),
|
StreamChatTheme.of(context)
|
||||||
Colors.white.withOpacity(0.05),
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(0.02),
|
||||||
|
StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.white
|
||||||
|
.withOpacity(0.05),
|
||||||
],
|
],
|
||||||
stops: [0, 1],
|
stops: [0, 1],
|
||||||
),
|
),
|
||||||
@@ -250,13 +259,17 @@ class _NewChatScreenState extends State<NewChatScreen> {
|
|||||||
horizontal: 8,
|
horizontal: 8,
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
_isSearchActive
|
_isSearchActive
|
||||||
? "Matches for \"$_userNameQuery\""
|
? "Matches for \"$_userNameQuery\""
|
||||||
: 'On the platform',
|
: 'On the platform',
|
||||||
style: TextStyle(
|
style: StreamChatTheme.of(context)
|
||||||
color: Colors.black.withOpacity(0.5),
|
.textTheme
|
||||||
),
|
.footnote
|
||||||
),
|
.copyWith(
|
||||||
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(.5))),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
@@ -316,7 +329,17 @@ class _NewChatScreenState extends State<NewChatScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'No user matches these keywords...'),
|
'No user matches these keywords...',
|
||||||
|
style: StreamChatTheme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.footnote
|
||||||
|
.copyWith(
|
||||||
|
color: StreamChatTheme.of(
|
||||||
|
context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(.5)),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -340,7 +363,10 @@ class _NewChatScreenState extends State<NewChatScreen> {
|
|||||||
'No chats here yet...',
|
'No chats here yet...',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
color: Colors.black.withOpacity(.5),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(.5),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3,9 +3,8 @@ import 'dart:async';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
import 'group_chat_details_screen.dart';
|
|
||||||
import 'search_text_field.dart';
|
|
||||||
import 'routes/routes.dart';
|
import 'routes/routes.dart';
|
||||||
|
import 'search_text_field.dart';
|
||||||
|
|
||||||
class NewGroupChatScreen extends StatefulWidget {
|
class NewGroupChatScreen extends StatefulWidget {
|
||||||
@override
|
@override
|
||||||
@@ -51,23 +50,24 @@ class _NewGroupChatScreenState extends State<NewGroupChatScreen> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SafeArea(
|
return Scaffold(
|
||||||
child: Scaffold(
|
backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow,
|
||||||
backgroundColor: Color.fromRGBO(252, 252, 252, 1),
|
body: SafeArea(
|
||||||
body: NestedScrollView(
|
child: NestedScrollView(
|
||||||
floatHeaderSlivers: true,
|
floatHeaderSlivers: true,
|
||||||
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
|
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
|
||||||
return <Widget>[
|
return <Widget>[
|
||||||
SliverAppBar(
|
SliverAppBar(
|
||||||
|
brightness: Theme.of(context).brightness,
|
||||||
pinned: true,
|
pinned: true,
|
||||||
forceElevated: true,
|
forceElevated: true,
|
||||||
elevation: 1,
|
elevation: 1,
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: StreamChatTheme.of(context).colorTheme.white,
|
||||||
leading: const StreamBackButton(),
|
leading: const StreamBackButton(),
|
||||||
title: Text(
|
title: Text(
|
||||||
'Add Group Members',
|
'Add Group Members',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.black,
|
color: StreamChatTheme.of(context).colorTheme.black,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -76,7 +76,8 @@ class _NewGroupChatScreenState extends State<NewGroupChatScreen> {
|
|||||||
if (_selectedUsers.isNotEmpty)
|
if (_selectedUsers.isNotEmpty)
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: StreamSvgIcon.arrow_right(
|
icon: StreamSvgIcon.arrow_right(
|
||||||
color: Color(0xFF006CFF),
|
color:
|
||||||
|
StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||||
),
|
),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final updatedList = await Navigator.pushNamed(
|
final updatedList = await Navigator.pushNamed(
|
||||||
@@ -137,18 +138,21 @@ class _NewGroupChatScreenState extends State<NewGroupChatScreen> {
|
|||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white,
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.white,
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: Colors.grey.shade100,
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.whiteSnow,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Padding(
|
child: StreamSvgIcon.close(
|
||||||
padding: const EdgeInsets.all(0.0),
|
color: StreamChatTheme.of(context)
|
||||||
child: StreamSvgIcon.close(
|
.colorTheme
|
||||||
color: Colors.black,
|
.black,
|
||||||
size: 24,
|
size: 24,
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -180,8 +184,14 @@ class _NewGroupChatScreenState extends State<NewGroupChatScreen> {
|
|||||||
begin: Alignment.centerLeft,
|
begin: Alignment.centerLeft,
|
||||||
end: Alignment.centerRight,
|
end: Alignment.centerRight,
|
||||||
colors: [
|
colors: [
|
||||||
Colors.black.withOpacity(0.02),
|
StreamChatTheme.of(context)
|
||||||
Colors.white.withOpacity(0.05),
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(0.02),
|
||||||
|
StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.white
|
||||||
|
.withOpacity(0.05),
|
||||||
],
|
],
|
||||||
stops: [0, 1],
|
stops: [0, 1],
|
||||||
),
|
),
|
||||||
@@ -196,7 +206,10 @@ class _NewGroupChatScreenState extends State<NewGroupChatScreen> {
|
|||||||
? 'Matches for \"$_userNameQuery\"'
|
? 'Matches for \"$_userNameQuery\"'
|
||||||
: 'On the platform',
|
: 'On the platform',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.black.withOpacity(0.5),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(0.5),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -261,7 +274,17 @@ class _NewGroupChatScreenState extends State<NewGroupChatScreen> {
|
|||||||
color: Colors.grey,
|
color: Colors.grey,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text('No user matches these keywords...'),
|
Text(
|
||||||
|
'No user matches these keywords...',
|
||||||
|
style: StreamChatTheme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.footnote
|
||||||
|
.copyWith(
|
||||||
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(.5)),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -292,7 +315,7 @@ class _HeaderDelegate extends SliverPersistentHeaderDelegate {
|
|||||||
Widget build(
|
Widget build(
|
||||||
BuildContext context, double shrinkOffset, bool overlapsContent) {
|
BuildContext context, double shrinkOffset, bool overlapsContent) {
|
||||||
return Container(
|
return Container(
|
||||||
color: Colors.white,
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
child: child,
|
child: child,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ class SearchTextField extends StatelessWidget {
|
|||||||
return Container(
|
return Container(
|
||||||
height: 36,
|
height: 36,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white,
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: Colors.grey.shade300,
|
color: StreamChatTheme.of(context).colorTheme.greyWhisper,
|
||||||
),
|
),
|
||||||
borderRadius: BorderRadius.circular(24),
|
borderRadius: BorderRadius.circular(24),
|
||||||
),
|
),
|
||||||
@@ -40,6 +40,7 @@ class SearchTextField extends StatelessWidget {
|
|||||||
controller: controller,
|
controller: controller,
|
||||||
onChanged: onChanged,
|
onChanged: onChanged,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
|
prefixText: ' ',
|
||||||
prefixIconConstraints: BoxConstraints.tight(Size(40, 24)),
|
prefixIconConstraints: BoxConstraints.tight(Size(40, 24)),
|
||||||
prefixIcon: Padding(
|
prefixIcon: Padding(
|
||||||
padding: const EdgeInsets.only(
|
padding: const EdgeInsets.only(
|
||||||
@@ -47,15 +48,16 @@ class SearchTextField extends StatelessWidget {
|
|||||||
right: 8,
|
right: 8,
|
||||||
),
|
),
|
||||||
child: StreamSvgIcon.search(
|
child: StreamSvgIcon.search(
|
||||||
color: Colors.black,
|
color: StreamChatTheme.of(context).colorTheme.black,
|
||||||
size: 24,
|
size: 24,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
hintText: hintText,
|
hintText: hintText,
|
||||||
hintStyle: TextStyle(
|
hintStyle: StreamChatTheme.of(context).textTheme.body.copyWith(
|
||||||
color: Colors.black.withOpacity(0.5),
|
color: StreamChatTheme.of(context)
|
||||||
fontSize: 14,
|
.colorTheme
|
||||||
),
|
.black
|
||||||
|
.withOpacity(.5)),
|
||||||
contentPadding: const EdgeInsets.all(0),
|
contentPadding: const EdgeInsets.all(0),
|
||||||
border: OutlineInputBorder(
|
border: OutlineInputBorder(
|
||||||
borderSide: BorderSide.none,
|
borderSide: BorderSide.none,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:yaml/yaml.dart';
|
import 'package:yaml/yaml.dart';
|
||||||
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
class StreamVersion extends StatelessWidget {
|
class StreamVersion extends StatelessWidget {
|
||||||
const StreamVersion({
|
const StreamVersion({
|
||||||
@@ -28,7 +29,8 @@ class StreamVersion extends StatelessWidget {
|
|||||||
'Stream SDK v ${streamChatDep}',
|
'Stream SDK v ${streamChatDep}',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14.5,
|
fontSize: 14.5,
|
||||||
color: Colors.black.withOpacity(.13),
|
color:
|
||||||
|
StreamChatTheme.of(context).colorTheme.black.withOpacity(.13),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
name: example
|
name: example
|
||||||
description: A new Flutter project.
|
description: A new Flutter project.
|
||||||
version: 1.0.94+97
|
version: 1.0.102+105
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.2.2 <3.0.0"
|
sdk: ">=2.2.2 <3.0.0"
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import 'dart:io';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat/stream_chat.dart';
|
import 'package:stream_chat/stream_chat.dart';
|
||||||
|
|
||||||
|
import '../stream_chat_flutter.dart';
|
||||||
|
|
||||||
class AttachmentError extends StatelessWidget {
|
class AttachmentError extends StatelessWidget {
|
||||||
final Attachment attachment;
|
final Attachment attachment;
|
||||||
final Size size;
|
final Size size;
|
||||||
@@ -23,12 +25,12 @@ class AttachmentError extends StatelessWidget {
|
|||||||
return Center(
|
return Center(
|
||||||
child: Container(
|
child: Container(
|
||||||
width: size?.width,
|
width: size?.width,
|
||||||
height: size?.height,
|
height: size?.height ?? 200,
|
||||||
color: Color(0xffd0021B).withOpacity(.1),
|
color: StreamChatTheme.of(context).colorTheme.accentRed.withOpacity(.1),
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.error_outline,
|
Icons.error_outline,
|
||||||
color: Colors.white,
|
color: StreamChatTheme.of(context).colorTheme.black,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ class AttachmentTitle extends StatelessWidget {
|
|||||||
attachment.title,
|
attachment.title,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: messageTheme.messageText.copyWith(
|
style: messageTheme.messageText.copyWith(
|
||||||
color: StreamChatTheme.of(context).accentColor,
|
color: StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
|
import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
|
||||||
import 'package:stream_chat_flutter/src/unread_indicator.dart';
|
import 'package:stream_chat_flutter/src/unread_indicator.dart';
|
||||||
|
|
||||||
|
import '../stream_chat_flutter.dart';
|
||||||
|
|
||||||
class StreamBackButton extends StatelessWidget {
|
class StreamBackButton extends StatelessWidget {
|
||||||
const StreamBackButton({
|
const StreamBackButton({
|
||||||
Key key,
|
Key key,
|
||||||
@@ -35,9 +37,7 @@ class StreamBackButton extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
child: StreamSvgIcon.left(
|
child: StreamSvgIcon.left(
|
||||||
size: 24,
|
size: 24,
|
||||||
color: Theme.of(context).brightness == Brightness.dark
|
color: StreamChatTheme.of(context).colorTheme.black,
|
||||||
? Colors.white
|
|
||||||
: Colors.black,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ class ChannelBottomSheet extends StatelessWidget {
|
|||||||
ListTile(
|
ListTile(
|
||||||
leading: StreamSvgIcon.userRemove(
|
leading: StreamSvgIcon.userRemove(
|
||||||
size: 24,
|
size: 24,
|
||||||
color: Color(0xff7A7A7A),
|
color: StreamChatTheme.of(context).colorTheme.grey,
|
||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
'Leave Group',
|
'Leave Group',
|
||||||
@@ -106,13 +106,13 @@ class ChannelBottomSheet extends StatelessWidget {
|
|||||||
?.role))
|
?.role))
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: StreamSvgIcon.delete(
|
leading: StreamSvgIcon.delete(
|
||||||
color: Color(0xFFFF3742),
|
color: StreamChatTheme.of(context).colorTheme.accentRed,
|
||||||
size: 24,
|
size: 24,
|
||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
'Delete chat',
|
'Delete chat',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Color(0xFFFF3742),
|
color: StreamChatTheme.of(context).colorTheme.accentRed,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
@@ -124,7 +124,7 @@ class ChannelBottomSheet extends StatelessWidget {
|
|||||||
'Are you sure you want to delete this conversation?',
|
'Are you sure you want to delete this conversation?',
|
||||||
cancelText: 'CANCEL',
|
cancelText: 'CANCEL',
|
||||||
icon: StreamSvgIcon.delete(
|
icon: StreamSvgIcon.delete(
|
||||||
color: Colors.red,
|
color: StreamChatTheme.of(context).colorTheme.accentRed,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
var channel = StreamChannel.of(context).channel;
|
var channel = StreamChannel.of(context).channel;
|
||||||
|
|||||||
@@ -52,6 +52,9 @@ class ChannelImage extends StatelessWidget {
|
|||||||
this.onTap,
|
this.onTap,
|
||||||
this.showOnlineStatus = true,
|
this.showOnlineStatus = true,
|
||||||
this.borderRadius,
|
this.borderRadius,
|
||||||
|
this.selected = false,
|
||||||
|
this.selectionColor,
|
||||||
|
this.selectionThickness = 4,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
final BorderRadius borderRadius;
|
final BorderRadius borderRadius;
|
||||||
@@ -67,6 +70,12 @@ class ChannelImage extends StatelessWidget {
|
|||||||
|
|
||||||
final bool showOnlineStatus;
|
final bool showOnlineStatus;
|
||||||
|
|
||||||
|
final bool selected;
|
||||||
|
|
||||||
|
final Color selectionColor;
|
||||||
|
|
||||||
|
final double selectionThickness;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final streamChat = StreamChat.of(context);
|
final streamChat = StreamChat.of(context);
|
||||||
@@ -94,11 +103,11 @@ class ChannelImage extends StatelessWidget {
|
|||||||
.channelPreviewTheme
|
.channelPreviewTheme
|
||||||
.avatarTheme
|
.avatarTheme
|
||||||
.constraints,
|
.constraints,
|
||||||
onTap: onTap != null
|
onTap: onTap != null ? (_) => onTap() : null,
|
||||||
? (_) {
|
selected: selected,
|
||||||
onTap();
|
selectionColor: selectionColor ??
|
||||||
}
|
StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||||
: null,
|
selectionThickness: selectionThickness,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -111,16 +120,21 @@ class ChannelImage extends StatelessWidget {
|
|||||||
.toList();
|
.toList();
|
||||||
return GroupImage(
|
return GroupImage(
|
||||||
images: images,
|
images: images,
|
||||||
|
borderRadius: borderRadius,
|
||||||
constraints: constraints ??
|
constraints: constraints ??
|
||||||
StreamChatTheme.of(context)
|
StreamChatTheme.of(context)
|
||||||
.channelPreviewTheme
|
.channelPreviewTheme
|
||||||
.avatarTheme
|
.avatarTheme
|
||||||
.constraints,
|
.constraints,
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
|
selected: selected,
|
||||||
|
selectionColor: selectionColor ??
|
||||||
|
StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||||
|
selectionThickness: selectionThickness,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ClipRRect(
|
Widget child = ClipRRect(
|
||||||
borderRadius: borderRadius ??
|
borderRadius: borderRadius ??
|
||||||
StreamChatTheme.of(context)
|
StreamChatTheme.of(context)
|
||||||
.channelPreviewTheme
|
.channelPreviewTheme
|
||||||
@@ -133,7 +147,7 @@ class ChannelImage extends StatelessWidget {
|
|||||||
.avatarTheme
|
.avatarTheme
|
||||||
.constraints,
|
.constraints,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: StreamChatTheme.of(context).accentColor,
|
color: StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||||
),
|
),
|
||||||
child: Stack(
|
child: Stack(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
@@ -149,7 +163,9 @@ class ChannelImage extends StatelessWidget {
|
|||||||
? snapshot.data['name'][0]
|
? snapshot.data['name'][0]
|
||||||
: '',
|
: '',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.white,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -169,6 +185,30 @@ class ChannelImage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
if (selected) {
|
||||||
|
child = ClipRRect(
|
||||||
|
borderRadius: (borderRadius ??
|
||||||
|
StreamChatTheme.of(context)
|
||||||
|
.ownMessageTheme
|
||||||
|
.avatarTheme
|
||||||
|
.borderRadius) +
|
||||||
|
BorderRadius.circular(selectionThickness),
|
||||||
|
child: Container(
|
||||||
|
constraints: constraints ??
|
||||||
|
StreamChatTheme.of(context)
|
||||||
|
.ownMessageTheme
|
||||||
|
.avatarTheme
|
||||||
|
.constraints,
|
||||||
|
color: selectionColor ??
|
||||||
|
StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(selectionThickness),
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return child;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ class ChannelInfo extends StatelessWidget {
|
|||||||
child: Text(
|
child: Text(
|
||||||
'Try Again',
|
'Try Again',
|
||||||
style: textStyle.copyWith(
|
style: textStyle.copyWith(
|
||||||
color: Color(0xFF006CFF),
|
color: StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
var color;
|
var color;
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case ConnectionStatus.connected:
|
case ConnectionStatus.connected:
|
||||||
color = Color(0xFF006CFF);
|
color = StreamChatTheme.of(context).colorTheme.accentBlue;
|
||||||
break;
|
break;
|
||||||
case ConnectionStatus.connecting:
|
case ConnectionStatus.connecting:
|
||||||
color = Colors.grey;
|
color = Colors.grey;
|
||||||
@@ -144,13 +144,8 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
|
|
||||||
Widget _buildConnectedTitleState(BuildContext context) => Text(
|
Widget _buildConnectedTitleState(BuildContext context) => Text(
|
||||||
'Stream Chat',
|
'Stream Chat',
|
||||||
style: StreamChatTheme.of(context)
|
style: StreamChatTheme.of(context).textTheme.headlineBold.copyWith(
|
||||||
.channelTheme
|
color: StreamChatTheme.of(context).colorTheme.black,
|
||||||
.channelHeaderTheme
|
|
||||||
.title
|
|
||||||
.copyWith(
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -210,7 +205,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
.copyWith(
|
.copyWith(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: Color(0xFF006CFF),
|
color: StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
+189
-95
@@ -74,6 +74,8 @@ class ChannelListView extends StatefulWidget {
|
|||||||
this.onStartChatPressed,
|
this.onStartChatPressed,
|
||||||
this.swipeToAction = false,
|
this.swipeToAction = false,
|
||||||
this.pullToRefresh = true,
|
this.pullToRefresh = true,
|
||||||
|
this.crossAxisCount = 1,
|
||||||
|
this.selectedChannels = const [],
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
/// The builder that will be used in case of error
|
/// The builder that will be used in case of error
|
||||||
@@ -134,6 +136,11 @@ class ChannelListView extends StatefulWidget {
|
|||||||
/// Callback used in the default empty list widget
|
/// Callback used in the default empty list widget
|
||||||
final VoidCallback onStartChatPressed;
|
final VoidCallback onStartChatPressed;
|
||||||
|
|
||||||
|
/// The number of children in the cross axis.
|
||||||
|
final int crossAxisCount;
|
||||||
|
|
||||||
|
final List<Channel> selectedChannels;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_ChannelListViewState createState() => _ChannelListViewState();
|
_ChannelListViewState createState() => _ChannelListViewState();
|
||||||
}
|
}
|
||||||
@@ -203,16 +210,18 @@ class _ChannelListViewState extends State<ChannelListView>
|
|||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: StreamSvgIcon.message(
|
child: StreamSvgIcon.message(
|
||||||
size: 136,
|
size: 136,
|
||||||
color: Color(0xffDBDBDB),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.greyGainsboro,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
'Let’s start chatting!',
|
'Let’s start chatting!',
|
||||||
style: TextStyle(
|
style: StreamChatTheme.of(context)
|
||||||
fontSize: 16,
|
.textTheme
|
||||||
),
|
.headline,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
@@ -223,10 +232,14 @@ class _ChannelListViewState extends State<ChannelListView>
|
|||||||
child: Text(
|
child: Text(
|
||||||
'How about sending your first message to a friend?',
|
'How about sending your first message to a friend?',
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: TextStyle(
|
style: StreamChatTheme.of(context)
|
||||||
fontSize: 14,
|
.textTheme
|
||||||
color: Color(0xff7A7A7A),
|
.body
|
||||||
),
|
.copyWith(
|
||||||
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.grey,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -242,11 +255,14 @@ class _ChannelListViewState extends State<ChannelListView>
|
|||||||
onPressed: widget.onStartChatPressed,
|
onPressed: widget.onStartChatPressed,
|
||||||
child: Text(
|
child: Text(
|
||||||
'Start a chat',
|
'Start a chat',
|
||||||
style: TextStyle(
|
style: StreamChatTheme.of(context)
|
||||||
color:
|
.textTheme
|
||||||
StreamChatTheme.of(context).accentColor,
|
.bodyBold
|
||||||
fontWeight: FontWeight.bold,
|
.copyWith(
|
||||||
),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.accentBlue,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -259,22 +275,33 @@ class _ChannelListViewState extends State<ChannelListView>
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (channels.isNotEmpty) {
|
if (channels.isNotEmpty) {
|
||||||
child = ListView.custom(
|
if (widget.crossAxisCount > 1) {
|
||||||
physics: AlwaysScrollableScrollPhysics(),
|
child = GridView.builder(
|
||||||
controller: _scrollController,
|
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
childrenDelegate: SliverChildBuilderDelegate(
|
crossAxisCount: widget.crossAxisCount),
|
||||||
(context, i) {
|
itemCount: channels.length,
|
||||||
return _itemBuilder(context, i, channels);
|
physics: AlwaysScrollableScrollPhysics(),
|
||||||
|
controller: _scrollController,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return _gridItemBuilder(context, index, channels);
|
||||||
},
|
},
|
||||||
childCount: (channels.length * 2) + 1,
|
);
|
||||||
findChildIndexCallback: (key) {
|
} else {
|
||||||
final ValueKey<String> valueKey = key;
|
child = ListView.separated(
|
||||||
final index = channels.indexWhere(
|
physics: AlwaysScrollableScrollPhysics(),
|
||||||
(channel) => 'CHANNEL-${channel.id}' == valueKey.value);
|
itemCount:
|
||||||
return index != -1 ? (index * 2) : null;
|
channels.isNotEmpty ? channels.length + 1 : channels.length,
|
||||||
|
separatorBuilder: (_, index) {
|
||||||
|
if (widget.separatorBuilder != null) {
|
||||||
|
return widget.separatorBuilder(context, index);
|
||||||
|
}
|
||||||
|
return _separatorBuilder(context, index);
|
||||||
},
|
},
|
||||||
),
|
itemBuilder: (context, index) {
|
||||||
);
|
return _listItemBuilder(context, index, channels);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,11 +319,13 @@ class _ChannelListViewState extends State<ChannelListView>
|
|||||||
children: List.generate(
|
children: List.generate(
|
||||||
25,
|
25,
|
||||||
(i) {
|
(i) {
|
||||||
if (i % 2 != 0) {
|
if (widget.crossAxisCount == 1) {
|
||||||
if (widget.separatorBuilder != null) {
|
if (i % 2 != 0) {
|
||||||
return widget.separatorBuilder(context, i);
|
if (widget.separatorBuilder != null) {
|
||||||
|
return widget.separatorBuilder(context, i);
|
||||||
|
}
|
||||||
|
return _separatorBuilder(context, i);
|
||||||
}
|
}
|
||||||
return _separatorBuilder(context, i);
|
|
||||||
}
|
}
|
||||||
return _buildLoadingItem();
|
return _buildLoadingItem();
|
||||||
},
|
},
|
||||||
@@ -305,63 +334,96 @@ class _ChannelListViewState extends State<ChannelListView>
|
|||||||
}
|
}
|
||||||
|
|
||||||
Shimmer _buildLoadingItem() {
|
Shimmer _buildLoadingItem() {
|
||||||
return Shimmer.fromColors(
|
if (widget.crossAxisCount > 1) {
|
||||||
baseColor: Color(0xffE5E5E5),
|
return Shimmer.fromColors(
|
||||||
highlightColor: Color(0xffffffff),
|
baseColor: StreamChatTheme.of(context).colorTheme.greyGainsboro,
|
||||||
child: ListTile(
|
highlightColor: StreamChatTheme.of(context).colorTheme.whiteSmoke,
|
||||||
leading: Container(
|
child: Column(
|
||||||
decoration: BoxDecoration(
|
children: [
|
||||||
color: Colors.white,
|
SizedBox(
|
||||||
shape: BoxShape.circle,
|
height: 4.0,
|
||||||
),
|
),
|
||||||
constraints: BoxConstraints.tightFor(
|
Row(
|
||||||
height: 40,
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
width: 40,
|
children: [
|
||||||
),
|
for (int i = 0; i < widget.crossAxisCount; i++)
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
),
|
||||||
|
constraints: BoxConstraints.tightFor(
|
||||||
|
height: 70,
|
||||||
|
width: 70,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 16.0,
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
title: Align(
|
);
|
||||||
alignment: Alignment.centerLeft,
|
} else {
|
||||||
child: Container(
|
return Shimmer.fromColors(
|
||||||
|
baseColor: StreamChatTheme.of(context).colorTheme.greyGainsboro,
|
||||||
|
highlightColor: StreamChatTheme.of(context).colorTheme.whiteSmoke,
|
||||||
|
child: ListTile(
|
||||||
|
leading: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white,
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
borderRadius: BorderRadius.circular(11),
|
shape: BoxShape.circle,
|
||||||
),
|
),
|
||||||
constraints: BoxConstraints.tightFor(
|
constraints: BoxConstraints.tightFor(
|
||||||
height: 16,
|
height: 40,
|
||||||
width: 82,
|
width: 40,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
title: Align(
|
||||||
subtitle: Row(
|
alignment: Alignment.centerLeft,
|
||||||
children: [
|
child: Container(
|
||||||
Align(
|
|
||||||
alignment: Alignment.centerLeft,
|
|
||||||
child: Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.white,
|
|
||||||
borderRadius: BorderRadius.circular(11),
|
|
||||||
),
|
|
||||||
constraints: BoxConstraints.tightFor(
|
|
||||||
height: 16,
|
|
||||||
width: 238,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
margin: const EdgeInsets.only(left: 16),
|
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white,
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
borderRadius: BorderRadius.circular(11),
|
borderRadius: BorderRadius.circular(11),
|
||||||
),
|
),
|
||||||
constraints: BoxConstraints.tightFor(
|
constraints: BoxConstraints.tightFor(
|
||||||
height: 16,
|
height: 16,
|
||||||
width: 42,
|
width: 82,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
|
subtitle: Row(
|
||||||
|
children: [
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
|
borderRadius: BorderRadius.circular(11),
|
||||||
|
),
|
||||||
|
constraints: BoxConstraints.tightFor(
|
||||||
|
height: 16,
|
||||||
|
width: 238,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
margin: const EdgeInsets.only(left: 16),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
|
borderRadius: BorderRadius.circular(11),
|
||||||
|
),
|
||||||
|
constraints: BoxConstraints.tightFor(
|
||||||
|
height: 16,
|
||||||
|
width: 42,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildErrorWidget(
|
Widget _buildErrorWidget(
|
||||||
@@ -428,20 +490,10 @@ class _ChannelListViewState extends State<ChannelListView>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _itemBuilder(context, int i, List<Channel> channels) {
|
Widget _listItemBuilder(BuildContext context, int i, List<Channel> channels) {
|
||||||
if (i % 2 != 0) {
|
|
||||||
if (widget.separatorBuilder != null) {
|
|
||||||
return widget.separatorBuilder(context, i);
|
|
||||||
}
|
|
||||||
return _separatorBuilder(context, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
i = i ~/ 2;
|
|
||||||
|
|
||||||
final channelsProvider = ChannelsBloc.of(context);
|
final channelsProvider = ChannelsBloc.of(context);
|
||||||
if (i < channels.length) {
|
if (i < channels.length) {
|
||||||
final channel = channels[i];
|
final channel = channels[i];
|
||||||
|
|
||||||
ChannelTapCallback onTap;
|
ChannelTapCallback onTap;
|
||||||
if (widget.onChannelTap != null) {
|
if (widget.onChannelTap != null) {
|
||||||
onTap = widget.onChannelTap;
|
onTap = widget.onChannelTap;
|
||||||
@@ -493,9 +545,7 @@ class _ChannelListViewState extends State<ChannelListView>
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
final backgroundColor =
|
final backgroundColor =
|
||||||
Theme.of(context).brightness == Brightness.light
|
StreamChatTheme.of(context).colorTheme.whiteSmoke;
|
||||||
? Color(0xffEBEBEB)
|
|
||||||
: Color(0xff141414);
|
|
||||||
child = Slidable(
|
child = Slidable(
|
||||||
enabled: widget.swipeToAction,
|
enabled: widget.swipeToAction,
|
||||||
actionPane: SlidableBehindActionPane(),
|
actionPane: SlidableBehindActionPane(),
|
||||||
@@ -535,7 +585,7 @@ class _ChannelListViewState extends State<ChannelListView>
|
|||||||
IconSlideAction(
|
IconSlideAction(
|
||||||
color: backgroundColor,
|
color: backgroundColor,
|
||||||
iconWidget: StreamSvgIcon.delete(
|
iconWidget: StreamSvgIcon.delete(
|
||||||
color: Color(0xFFFF3742),
|
color: StreamChatTheme.of(context).colorTheme.accentRed,
|
||||||
),
|
),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
final res = await showConfirmationDialog(
|
final res = await showConfirmationDialog(
|
||||||
@@ -546,7 +596,9 @@ class _ChannelListViewState extends State<ChannelListView>
|
|||||||
'Are you sure you want to delete this conversation?',
|
'Are you sure you want to delete this conversation?',
|
||||||
cancelText: 'CANCEL',
|
cancelText: 'CANCEL',
|
||||||
icon: StreamSvgIcon.delete(
|
icon: StreamSvgIcon.delete(
|
||||||
color: Color(0xFFFF3742),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.accentRed,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
if (res == true) {
|
if (res == true) {
|
||||||
@@ -556,7 +608,7 @@ class _ChannelListViewState extends State<ChannelListView>
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
child: Container(
|
child: Container(
|
||||||
color: StreamChatTheme.of(context).backgroundColor,
|
color: StreamChatTheme.of(context).colorTheme.whiteSnow,
|
||||||
child: ChannelPreview(
|
child: ChannelPreview(
|
||||||
onLongPress: widget.onChannelLongPress,
|
onLongPress: widget.onChannelLongPress,
|
||||||
channel: channel,
|
channel: channel,
|
||||||
@@ -581,6 +633,47 @@ class _ChannelListViewState extends State<ChannelListView>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _gridItemBuilder(BuildContext context, int i, List<Channel> channels) {
|
||||||
|
var channel = channels[i];
|
||||||
|
|
||||||
|
var selected = widget.selectedChannels.contains(channel);
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
key: ValueKey<String>('CHANNEL-${channel.id}'),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
ChannelImage(
|
||||||
|
channel: channel,
|
||||||
|
borderRadius: BorderRadius.circular(32),
|
||||||
|
selected: selected,
|
||||||
|
constraints: BoxConstraints.tightFor(
|
||||||
|
width: 64,
|
||||||
|
height: 64,
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
|
widget.onChannelTap(channel, null);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
SizedBox(height: 7),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||||
|
child: StreamChannel(
|
||||||
|
child: ChannelName(
|
||||||
|
textStyle: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
channel: channel,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Widget _buildQueryProgressIndicator(
|
Widget _buildQueryProgressIndicator(
|
||||||
context,
|
context,
|
||||||
ChannelsBlocState channelsProvider,
|
ChannelsBlocState channelsProvider,
|
||||||
@@ -591,7 +684,10 @@ class _ChannelListViewState extends State<ChannelListView>
|
|||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
if (snapshot.hasError) {
|
if (snapshot.hasError) {
|
||||||
return Container(
|
return Container(
|
||||||
color: Color(0xffd0021B).withAlpha(26),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.accentRed
|
||||||
|
.withOpacity(.2),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||||
child: Center(
|
child: Center(
|
||||||
@@ -613,9 +709,7 @@ class _ChannelListViewState extends State<ChannelListView>
|
|||||||
Widget _separatorBuilder(context, i) {
|
Widget _separatorBuilder(context, i) {
|
||||||
return Container(
|
return Container(
|
||||||
height: 1,
|
height: 1,
|
||||||
color: Theme.of(context).brightness == Brightness.dark
|
color: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.08),
|
||||||
? Colors.white.withOpacity(0.1)
|
|
||||||
: Colors.black.withOpacity(0.1),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,9 @@ class ChannelPreview extends StatelessWidget {
|
|||||||
return Opacity(
|
return Opacity(
|
||||||
opacity: snapshot.data ? 0.5 : 1,
|
opacity: snapshot.data ? 0.5 : 1,
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
|
contentPadding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 8,
|
||||||
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (onTap != null) {
|
if (onTap != null) {
|
||||||
onTap(channel);
|
onTap(channel);
|
||||||
@@ -122,12 +125,16 @@ class ChannelPreview extends StatelessWidget {
|
|||||||
padding: const EdgeInsets.only(right: 4.0),
|
padding: const EdgeInsets.only(right: 4.0),
|
||||||
child: SendingIndicator(
|
child: SendingIndicator(
|
||||||
message: channel.state.lastMessage,
|
message: channel.state.lastMessage,
|
||||||
allRead: channel.state.read
|
size: StreamChatTheme.of(context)
|
||||||
|
.channelPreviewTheme
|
||||||
|
.lastMessageAt
|
||||||
|
.fontSize,
|
||||||
|
isMessageRead: channel.state.read
|
||||||
.where((element) => element.lastRead
|
.where((element) => element.lastRead
|
||||||
.isAfter(channel
|
.isAfter(channel
|
||||||
.state.lastMessage.createdAt))
|
.state.lastMessage.createdAt))
|
||||||
.length ==
|
.length ==
|
||||||
(channel.memberCount ?? 0),
|
((channel.memberCount ?? 0) - 1),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import 'package:emojis/emojis.dart';
|
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:jiffy/jiffy.dart';
|
import 'package:jiffy/jiffy.dart';
|
||||||
@@ -21,7 +20,7 @@ class _ChatInfoScreenState extends State<ChatInfoScreen> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final channel = StreamChannel.of(context).channel;
|
final channel = StreamChannel.of(context).channel;
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: Color(0xFFe6e6e6),
|
backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow,
|
||||||
body: ListView(
|
body: ListView(
|
||||||
children: [
|
children: [
|
||||||
_buildUserHeader(),
|
_buildUserHeader(),
|
||||||
@@ -47,7 +46,7 @@ class _ChatInfoScreenState extends State<ChatInfoScreen> {
|
|||||||
|
|
||||||
Widget _buildUserHeader() {
|
Widget _buildUserHeader() {
|
||||||
return Material(
|
return Material(
|
||||||
color: Colors.white,
|
color: StreamChatTheme.of(context).colorTheme.whiteSnow,
|
||||||
child: SafeArea(
|
child: SafeArea(
|
||||||
child: Stack(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
@@ -81,7 +80,11 @@ class _ChatInfoScreenState extends State<ChatInfoScreen> {
|
|||||||
child: Text(
|
child: Text(
|
||||||
widget.user.name,
|
widget.user.name,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.black.withOpacity(0.5), fontSize: 16.0),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(0.5),
|
||||||
|
fontSize: 16.0),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onTap: () {},
|
onTap: () {},
|
||||||
@@ -92,7 +95,9 @@ class _ChatInfoScreenState extends State<ChatInfoScreen> {
|
|||||||
top: 21,
|
top: 21,
|
||||||
left: 16,
|
left: 16,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
child: StreamSvgIcon.left(),
|
child: StreamSvgIcon.left(
|
||||||
|
color: StreamChatTheme.of(context).colorTheme.black,
|
||||||
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
},
|
},
|
||||||
@@ -113,7 +118,7 @@ class _ChatInfoScreenState extends State<ChatInfoScreen> {
|
|||||||
// title: 'Notifications',
|
// title: 'Notifications',
|
||||||
// leading: StreamSvgIcon.Icon_notification(
|
// leading: StreamSvgIcon.Icon_notification(
|
||||||
// size: 24.0,
|
// size: 24.0,
|
||||||
// color: Colors.black.withOpacity(0.5),
|
// color: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5),
|
||||||
// ),
|
// ),
|
||||||
// trailing: CupertinoSwitch(
|
// trailing: CupertinoSwitch(
|
||||||
// value: true,
|
// value: true,
|
||||||
@@ -128,7 +133,10 @@ class _ChatInfoScreenState extends State<ChatInfoScreen> {
|
|||||||
title: 'Mute user',
|
title: 'Mute user',
|
||||||
leading: StreamSvgIcon.mute(
|
leading: StreamSvgIcon.mute(
|
||||||
size: 23.0,
|
size: 23.0,
|
||||||
color: Colors.black.withOpacity(0.5),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(0.5),
|
||||||
),
|
),
|
||||||
trailing: snapshot.data == null
|
trailing: snapshot.data == null
|
||||||
? CircularProgressIndicator()
|
? CircularProgressIndicator()
|
||||||
@@ -149,7 +157,7 @@ class _ChatInfoScreenState extends State<ChatInfoScreen> {
|
|||||||
// title: 'Block User',
|
// title: 'Block User',
|
||||||
// leading: StreamSvgIcon.Icon_user_delete(
|
// leading: StreamSvgIcon.Icon_user_delete(
|
||||||
// size: 24.0,
|
// size: 24.0,
|
||||||
// color: Colors.black.withOpacity(0.5),
|
// color: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5),
|
||||||
// ),
|
// ),
|
||||||
// trailing: CupertinoSwitch(
|
// trailing: CupertinoSwitch(
|
||||||
// value: widget.user.banned,
|
// value: widget.user.banned,
|
||||||
@@ -167,7 +175,8 @@ class _ChatInfoScreenState extends State<ChatInfoScreen> {
|
|||||||
title: 'Photos & Videos',
|
title: 'Photos & Videos',
|
||||||
leading: StreamSvgIcon.pictures(
|
leading: StreamSvgIcon.pictures(
|
||||||
size: 32.0,
|
size: 32.0,
|
||||||
color: Colors.black.withOpacity(0.5),
|
color:
|
||||||
|
StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5),
|
||||||
),
|
),
|
||||||
trailing: StreamSvgIcon.right(),
|
trailing: StreamSvgIcon.right(),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
@@ -179,7 +188,8 @@ class _ChatInfoScreenState extends State<ChatInfoScreen> {
|
|||||||
title: 'Files',
|
title: 'Files',
|
||||||
leading: StreamSvgIcon.files(
|
leading: StreamSvgIcon.files(
|
||||||
size: 32.0,
|
size: 32.0,
|
||||||
color: Colors.black.withOpacity(0.5),
|
color:
|
||||||
|
StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5),
|
||||||
),
|
),
|
||||||
trailing: StreamSvgIcon.right(),
|
trailing: StreamSvgIcon.right(),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
@@ -191,7 +201,8 @@ class _ChatInfoScreenState extends State<ChatInfoScreen> {
|
|||||||
title: 'Shared groups',
|
title: 'Shared groups',
|
||||||
leading: StreamSvgIcon.Icon_group(
|
leading: StreamSvgIcon.Icon_group(
|
||||||
size: 24.0,
|
size: 24.0,
|
||||||
color: Colors.black.withOpacity(0.5),
|
color:
|
||||||
|
StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5),
|
||||||
),
|
),
|
||||||
trailing: StreamSvgIcon.right(),
|
trailing: StreamSvgIcon.right(),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
@@ -208,7 +219,7 @@ class _ChatInfoScreenState extends State<ChatInfoScreen> {
|
|||||||
|
|
||||||
Widget _buildDeleteListTile() {
|
Widget _buildDeleteListTile() {
|
||||||
return _OptionListTile(
|
return _OptionListTile(
|
||||||
title: 'Delete',
|
title: 'Delete conversation',
|
||||||
leading: StreamSvgIcon.delete(
|
leading: StreamSvgIcon.delete(
|
||||||
color: Colors.red,
|
color: Colors.red,
|
||||||
size: 24.0,
|
size: 24.0,
|
||||||
@@ -248,12 +259,20 @@ class _ChatInfoScreenState extends State<ChatInfoScreen> {
|
|||||||
if (otherMember.online) {
|
if (otherMember.online) {
|
||||||
alternativeWidget = Text(
|
alternativeWidget = Text(
|
||||||
'Online',
|
'Online',
|
||||||
style: TextStyle(color: Colors.black.withOpacity(0.5)),
|
style: TextStyle(
|
||||||
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(0.5)),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
alternativeWidget = Text(
|
alternativeWidget = Text(
|
||||||
'Last seen ${Jiffy(otherMember.lastActive).fromNow()}',
|
'Last seen ${Jiffy(otherMember.lastActive).fromNow()}',
|
||||||
style: TextStyle(color: Colors.black.withOpacity(0.5)),
|
style: TextStyle(
|
||||||
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(0.5)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -272,10 +291,10 @@ class _ChatInfoScreenState extends State<ChatInfoScreen> {
|
|||||||
),
|
),
|
||||||
child: Material(
|
child: Material(
|
||||||
shape: CircleBorder(),
|
shape: CircleBorder(),
|
||||||
color: Color(0xff20E070),
|
color: StreamChatTheme.of(context).colorTheme.accentGreen,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
color: Colors.white,
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
),
|
),
|
||||||
alternativeWidget,
|
alternativeWidget,
|
||||||
],
|
],
|
||||||
@@ -303,11 +322,11 @@ class _OptionListTile extends StatelessWidget {
|
|||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
color: Color(0xffe6e6e6),
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
height: 2.0,
|
height: 2.0,
|
||||||
),
|
),
|
||||||
Material(
|
Material(
|
||||||
color: Colors.white,
|
color: StreamChatTheme.of(context).colorTheme.whiteSnow,
|
||||||
child: Container(
|
child: Container(
|
||||||
height: 56.0,
|
height: 56.0,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
@@ -365,14 +384,16 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> {
|
|||||||
var chat = StreamChat.of(context);
|
var chat = StreamChat.of(context);
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
brightness: Theme.of(context).brightness,
|
brightness: Theme.of(context).brightness,
|
||||||
elevation: 1,
|
elevation: 1,
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
title: Text(
|
title: Text(
|
||||||
'Shared Groups',
|
'Shared Groups',
|
||||||
style: TextStyle(color: Colors.black, fontSize: 16.0),
|
style: TextStyle(
|
||||||
|
color: StreamChatTheme.of(context).colorTheme.black,
|
||||||
|
fontSize: 16.0),
|
||||||
),
|
),
|
||||||
leading: Center(
|
leading: Center(
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
@@ -381,7 +402,7 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> {
|
|||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
child: StreamSvgIcon.left(
|
child: StreamSvgIcon.left(
|
||||||
color: Colors.black,
|
color: StreamChatTheme.of(context).colorTheme.black,
|
||||||
size: 24.0,
|
size: 24.0,
|
||||||
),
|
),
|
||||||
width: 24.0,
|
width: 24.0,
|
||||||
@@ -389,7 +410,7 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
backgroundColor: StreamChatTheme.of(context).primaryColor,
|
backgroundColor: StreamChatTheme.of(context).colorTheme.white,
|
||||||
),
|
),
|
||||||
body: FutureBuilder<List<Channel>>(
|
body: FutureBuilder<List<Channel>>(
|
||||||
future: chat.client.queryChannels(
|
future: chat.client.queryChannels(
|
||||||
@@ -488,7 +509,11 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> {
|
|||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
'${channel.memberCount} members',
|
'${channel.memberCount} members',
|
||||||
style: TextStyle(color: Colors.black.withOpacity(0.5)),
|
style: TextStyle(
|
||||||
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(0.5)),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
@@ -496,7 +521,8 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> {
|
|||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
height: 1.0,
|
height: 1.0,
|
||||||
color: Color(0xffe6e6e6),
|
color:
|
||||||
|
StreamChatTheme.of(context).colorTheme.black.withOpacity(.08),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@@ -509,14 +535,16 @@ class _MediaDisplayScreen extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: StreamChatTheme.of(context).colorTheme.white,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
brightness: Theme.of(context).brightness,
|
brightness: Theme.of(context).brightness,
|
||||||
elevation: 1,
|
elevation: 1,
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
title: Text(
|
title: Text(
|
||||||
'Photos & Videos',
|
'Photos & Videos',
|
||||||
style: TextStyle(color: Colors.black, fontSize: 16.0),
|
style: TextStyle(
|
||||||
|
color: StreamChatTheme.of(context).colorTheme.black,
|
||||||
|
fontSize: 16.0),
|
||||||
),
|
),
|
||||||
leading: Center(
|
leading: Center(
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
@@ -525,7 +553,7 @@ class _MediaDisplayScreen extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
child: StreamSvgIcon.left(
|
child: StreamSvgIcon.left(
|
||||||
color: Colors.black,
|
color: StreamChatTheme.of(context).colorTheme.black,
|
||||||
size: 24.0,
|
size: 24.0,
|
||||||
),
|
),
|
||||||
width: 24.0,
|
width: 24.0,
|
||||||
@@ -533,7 +561,7 @@ class _MediaDisplayScreen extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
backgroundColor: StreamChatTheme.of(context).primaryColor,
|
backgroundColor: StreamChatTheme.of(context).colorTheme.white,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -543,14 +571,16 @@ class _FileDisplayScreen extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: StreamChatTheme.of(context).colorTheme.white,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
brightness: Theme.of(context).brightness,
|
brightness: Theme.of(context).brightness,
|
||||||
elevation: 1,
|
elevation: 1,
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
title: Text(
|
title: Text(
|
||||||
'Files',
|
'Files',
|
||||||
style: TextStyle(color: Colors.black, fontSize: 16.0),
|
style: TextStyle(
|
||||||
|
color: StreamChatTheme.of(context).colorTheme.black,
|
||||||
|
fontSize: 16.0),
|
||||||
),
|
),
|
||||||
leading: Center(
|
leading: Center(
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
@@ -559,7 +589,7 @@ class _FileDisplayScreen extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
child: StreamSvgIcon.left(
|
child: StreamSvgIcon.left(
|
||||||
color: Colors.black,
|
color: StreamChatTheme.of(context).colorTheme.black,
|
||||||
size: 24.0,
|
size: 24.0,
|
||||||
),
|
),
|
||||||
width: 24.0,
|
width: 24.0,
|
||||||
@@ -567,7 +597,7 @@ class _FileDisplayScreen extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
backgroundColor: StreamChatTheme.of(context).primaryColor,
|
backgroundColor: StreamChatTheme.of(context).colorTheme.white,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:jiffy/jiffy.dart';
|
import 'package:jiffy/jiffy.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||||
|
|
||||||
/// It shows a date divider depending on the date difference
|
/// It shows a date divider depending on the date difference
|
||||||
class DateDivider extends StatelessWidget {
|
class DateDivider extends StatelessWidget {
|
||||||
@@ -39,21 +40,17 @@ class DateDivider extends StatelessWidget {
|
|||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: (Theme.of(context).brightness == Brightness.light
|
color: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5),
|
||||||
? Colors.black
|
|
||||||
: Colors.white)
|
|
||||||
.withOpacity(0.5),
|
|
||||||
borderRadius: BorderRadius.circular(
|
borderRadius: BorderRadius.circular(
|
||||||
8,
|
8,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
dayInfo,
|
dayInfo,
|
||||||
style: TextStyle(
|
style: StreamChatTheme.of(context).textTheme.footnoteBold.copyWith(
|
||||||
fontSize: 12,
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
color: Colors.white,
|
fontWeight: FontWeight.bold,
|
||||||
fontWeight: FontWeight.bold,
|
),
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -41,8 +41,14 @@ class DeletedMessage extends StatelessWidget {
|
|||||||
side: borderSide ??
|
side: borderSide ??
|
||||||
BorderSide(
|
BorderSide(
|
||||||
color: Theme.of(context).brightness == Brightness.dark
|
color: Theme.of(context).brightness == Brightness.dark
|
||||||
? Colors.white.withAlpha(24)
|
? StreamChatTheme.of(context)
|
||||||
: Colors.black.withAlpha(24),
|
.colorTheme
|
||||||
|
.white
|
||||||
|
.withAlpha(24)
|
||||||
|
: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withAlpha(24),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
@@ -58,8 +64,8 @@ class DeletedMessage extends StatelessWidget {
|
|||||||
style: messageTheme.messageText.copyWith(
|
style: messageTheme.messageText.copyWith(
|
||||||
fontStyle: FontStyle.italic,
|
fontStyle: FontStyle.italic,
|
||||||
color: (Theme.of(context).brightness == Brightness.dark
|
color: (Theme.of(context).brightness == Brightness.dark
|
||||||
? Colors.white
|
? StreamChatTheme.of(context).colorTheme.white
|
||||||
: Colors.black)
|
: StreamChatTheme.of(context).colorTheme.black)
|
||||||
.withOpacity(.5),
|
.withOpacity(.5),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
|
|||||||
import 'package:stream_chat_flutter/src/utils.dart';
|
import 'package:stream_chat_flutter/src/utils.dart';
|
||||||
import 'package:video_compress/video_compress.dart';
|
import 'package:video_compress/video_compress.dart';
|
||||||
import 'package:video_player/video_player.dart';
|
import 'package:video_player/video_player.dart';
|
||||||
|
|
||||||
import 'media_utils.dart';
|
import 'media_utils.dart';
|
||||||
|
|
||||||
enum FileAttachmentType { local, online }
|
enum FileAttachmentType { local, online }
|
||||||
@@ -61,13 +62,13 @@ class _FileAttachmentState extends State<FileAttachment> {
|
|||||||
child: Container(
|
child: Container(
|
||||||
width: widget.size?.width ?? 100,
|
width: widget.size?.width ?? 100,
|
||||||
height: 56.0,
|
height: 56.0,
|
||||||
margin: widget.trailing != null ? EdgeInsets.only(top: 4.0) : null,
|
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white,
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
borderRadius:
|
borderRadius:
|
||||||
widget.trailing != null ? BorderRadius.circular(16.0) : null,
|
widget.trailing != null ? BorderRadius.circular(16.0) : null,
|
||||||
border: widget.trailing != null
|
border: widget.trailing != null
|
||||||
? Border.fromBorderSide(BorderSide(color: Color(0xFFE6E6E6)))
|
? Border.fromBorderSide(BorderSide(
|
||||||
|
color: StreamChatTheme.of(context).colorTheme.greyWhisper))
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
@@ -88,10 +89,7 @@ class _FileAttachmentState extends State<FileAttachment> {
|
|||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
widget.attachment?.title ?? 'File',
|
widget.attachment?.title ?? 'File',
|
||||||
style: TextStyle(
|
style: StreamChatTheme.of(context).textTheme.bodyBold,
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
fontSize: 14.0,
|
|
||||||
),
|
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
@@ -100,10 +98,11 @@ class _FileAttachmentState extends State<FileAttachment> {
|
|||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'${getSizeText(widget.attachment.extraData['file_size'])}',
|
'${getSizeText(widget.attachment.extraData['file_size'])}',
|
||||||
style: TextStyle(
|
style: StreamChatTheme.of(context).textTheme.body.copyWith(
|
||||||
color: Colors.black.withOpacity(0.5),
|
color: StreamChatTheme.of(context)
|
||||||
fontSize: 14.0,
|
.colorTheme
|
||||||
),
|
.black
|
||||||
|
.withOpacity(0.5)),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -113,7 +112,7 @@ class _FileAttachmentState extends State<FileAttachment> {
|
|||||||
widget.trailing ??
|
widget.trailing ??
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: StreamSvgIcon.cloud_download(
|
icon: StreamSvgIcon.cloud_download(
|
||||||
color: Colors.black,
|
color: StreamChatTheme.of(context).colorTheme.black,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
launchURL(context, widget.attachment.assetUrl);
|
launchURL(context, widget.attachment.assetUrl);
|
||||||
@@ -148,7 +147,8 @@ class _FileAttachmentState extends State<FileAttachment> {
|
|||||||
width: 20.0,
|
width: 20.0,
|
||||||
height: 20.0,
|
height: 20.0,
|
||||||
child: CircularProgressIndicator(
|
child: CircularProgressIndicator(
|
||||||
backgroundColor: StreamChatTheme.of(context).accentColor,
|
backgroundColor:
|
||||||
|
StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -112,7 +112,10 @@ class GiphyAttachment extends StatelessWidget {
|
|||||||
bottom: 16,
|
bottom: 16,
|
||||||
left: 16,
|
left: 16,
|
||||||
child: Material(
|
child: Material(
|
||||||
color: Colors.black.withOpacity(.5),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(.5),
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
@@ -124,13 +127,16 @@ class GiphyAttachment extends StatelessWidget {
|
|||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
StreamSvgIcon.lightning(
|
StreamSvgIcon.lightning(
|
||||||
color: Colors.white,
|
color:
|
||||||
|
StreamChatTheme.of(context).colorTheme.white,
|
||||||
size: 16,
|
size: 16,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'GIPHY',
|
'GIPHY',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.white,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 11,
|
fontSize: 11,
|
||||||
),
|
),
|
||||||
@@ -202,7 +208,10 @@ class GiphyAttachment extends StatelessWidget {
|
|||||||
height: 4.0,
|
height: 4.0,
|
||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
color: Colors.black.withOpacity(0.2),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(0.2),
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
height: 0.5,
|
height: 0.5,
|
||||||
),
|
),
|
||||||
@@ -220,15 +229,24 @@ class GiphyAttachment extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
'Cancel',
|
'Cancel',
|
||||||
style: TextStyle(
|
style: StreamChatTheme.of(context)
|
||||||
fontWeight: FontWeight.bold,
|
.textTheme
|
||||||
color: Colors.black.withOpacity(0.5)),
|
.bodyBold
|
||||||
|
.copyWith(
|
||||||
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(0.5),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
width: 0.5,
|
width: 0.5,
|
||||||
color: Colors.black.withOpacity(0.2),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(0.2),
|
||||||
height: 50.0,
|
height: 50.0,
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
@@ -242,7 +260,9 @@ class GiphyAttachment extends StatelessWidget {
|
|||||||
child: Text(
|
child: Text(
|
||||||
'Send',
|
'Send',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: StreamChatTheme.of(context).accentColor,
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.accentBlue,
|
||||||
fontWeight: FontWeight.bold),
|
fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -263,7 +283,10 @@ class GiphyAttachment extends StatelessWidget {
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
StreamSvgIcon.eye(
|
StreamSvgIcon.eye(
|
||||||
color: Colors.black.withOpacity(0.5),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(0.5),
|
||||||
size: 16.0,
|
size: 16.0,
|
||||||
),
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
@@ -271,10 +294,14 @@ class GiphyAttachment extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'Only visible to you',
|
'Only visible to you',
|
||||||
style: TextStyle(
|
style: StreamChatTheme.of(context)
|
||||||
color: Colors.black.withOpacity(0.5),
|
.textTheme
|
||||||
fontSize: 12.0,
|
.footnote
|
||||||
),
|
.copyWith(
|
||||||
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(0.5)),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -331,7 +358,10 @@ class GiphyAttachment extends StatelessWidget {
|
|||||||
bottom: 8,
|
bottom: 8,
|
||||||
left: 8,
|
left: 8,
|
||||||
child: Material(
|
child: Material(
|
||||||
color: Colors.black.withOpacity(.5),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(.5),
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
@@ -343,13 +373,13 @@ class GiphyAttachment extends StatelessWidget {
|
|||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
StreamSvgIcon.lightning(
|
StreamSvgIcon.lightning(
|
||||||
color: Colors.white,
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
size: 16,
|
size: 16,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'GIPHY',
|
'GIPHY',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 11,
|
fontSize: 11,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -9,21 +9,33 @@ class GroupImage extends StatelessWidget {
|
|||||||
@required this.images,
|
@required this.images,
|
||||||
this.constraints,
|
this.constraints,
|
||||||
this.onTap,
|
this.onTap,
|
||||||
|
this.borderRadius,
|
||||||
|
this.selected = false,
|
||||||
|
this.selectionColor,
|
||||||
|
this.selectionThickness = 4,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
final List<String> images;
|
final List<String> images;
|
||||||
final BoxConstraints constraints;
|
final BoxConstraints constraints;
|
||||||
final VoidCallback onTap;
|
final VoidCallback onTap;
|
||||||
|
final bool selected;
|
||||||
|
final BorderRadius borderRadius;
|
||||||
|
final Color selectionColor;
|
||||||
|
final double selectionThickness;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return GestureDetector(
|
var avatar;
|
||||||
|
final streamChatTheme = StreamChatTheme.of(context);
|
||||||
|
|
||||||
|
avatar = GestureDetector(
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
child: ClipRRect(
|
child: ClipRRect(
|
||||||
borderRadius: StreamChatTheme.of(context)
|
borderRadius: borderRadius ??
|
||||||
.ownMessageTheme
|
StreamChatTheme.of(context)
|
||||||
.avatarTheme
|
.ownMessageTheme
|
||||||
.borderRadius,
|
.avatarTheme
|
||||||
|
.borderRadius,
|
||||||
child: Container(
|
child: Container(
|
||||||
constraints: constraints ??
|
constraints: constraints ??
|
||||||
StreamChatTheme.of(context)
|
StreamChatTheme.of(context)
|
||||||
@@ -31,7 +43,7 @@ class GroupImage extends StatelessWidget {
|
|||||||
.avatarTheme
|
.avatarTheme
|
||||||
.constraints,
|
.constraints,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: StreamChatTheme.of(context).accentColor,
|
color: StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||||
),
|
),
|
||||||
child: Flex(
|
child: Flex(
|
||||||
direction: Axis.vertical,
|
direction: Axis.vertical,
|
||||||
@@ -91,5 +103,25 @@ class GroupImage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (selected) {
|
||||||
|
avatar = ClipRRect(
|
||||||
|
borderRadius: (borderRadius ??
|
||||||
|
streamChatTheme.ownMessageTheme.avatarTheme.borderRadius) +
|
||||||
|
BorderRadius.circular(selectionThickness),
|
||||||
|
child: Container(
|
||||||
|
color: selectionColor ??
|
||||||
|
StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||||
|
height: 64.0,
|
||||||
|
width: 64.0,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(selectionThickness),
|
||||||
|
child: avatar,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return avatar;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:dio/dio.dart';
|
|
||||||
import 'package:image_gallery_saver/image_gallery_saver.dart';
|
import 'package:image_gallery_saver/image_gallery_saver.dart';
|
||||||
import '../stream_chat_flutter.dart';
|
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
|
||||||
|
import '../stream_chat_flutter.dart';
|
||||||
|
|
||||||
class ImageActionsModal extends StatelessWidget {
|
class ImageActionsModal extends StatelessWidget {
|
||||||
final Message message;
|
final Message message;
|
||||||
final String userName;
|
final String userName;
|
||||||
@@ -66,11 +67,12 @@ class ImageActionsModal extends StatelessWidget {
|
|||||||
padding: const EdgeInsets.only(top: 8.0),
|
padding: const EdgeInsets.only(top: 8.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
userName,
|
userName,
|
||||||
style: TextStyle(
|
style: StreamChatTheme.of(context)
|
||||||
fontSize: 16.0,
|
.textTheme
|
||||||
fontWeight: FontWeight.w700,
|
.headlineBold
|
||||||
color: Colors.white,
|
.copyWith(
|
||||||
),
|
color:
|
||||||
|
StreamChatTheme.of(context).colorTheme.white),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
@@ -78,14 +80,18 @@ class ImageActionsModal extends StatelessWidget {
|
|||||||
style: StreamChatTheme.of(context)
|
style: StreamChatTheme.of(context)
|
||||||
.channelPreviewTheme
|
.channelPreviewTheme
|
||||||
.subtitle
|
.subtitle
|
||||||
.copyWith(color: Colors.white.withOpacity(0.5)),
|
.copyWith(
|
||||||
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.white
|
||||||
|
.withOpacity(0.5)),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: StreamSvgIcon.close(
|
icon: StreamSvgIcon.close(
|
||||||
size: 24.0,
|
size: 24.0,
|
||||||
color: Colors.white,
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
@@ -104,10 +110,10 @@ class ImageActionsModal extends StatelessWidget {
|
|||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius: BorderRadius.circular(16),
|
||||||
),
|
),
|
||||||
color: Color(0xffe5e5e5),
|
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: ListTile.divideTiles(
|
children: ListTile.divideTiles(
|
||||||
|
color: StreamChatTheme.of(context).colorTheme.greyWhisper,
|
||||||
context: context,
|
context: context,
|
||||||
tiles: [
|
tiles: [
|
||||||
_buildButton(
|
_buildButton(
|
||||||
@@ -115,7 +121,10 @@ class ImageActionsModal extends StatelessWidget {
|
|||||||
'Reply',
|
'Reply',
|
||||||
StreamSvgIcon.Icon_curve_line_left_up(
|
StreamSvgIcon.Icon_curve_line_left_up(
|
||||||
size: 24.0,
|
size: 24.0,
|
||||||
color: Colors.black.withOpacity(0.5),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(0.5),
|
||||||
),
|
),
|
||||||
() {}),
|
() {}),
|
||||||
_buildButton(
|
_buildButton(
|
||||||
@@ -123,7 +132,8 @@ class ImageActionsModal extends StatelessWidget {
|
|||||||
'Show in Chat',
|
'Show in Chat',
|
||||||
StreamSvgIcon.eye(
|
StreamSvgIcon.eye(
|
||||||
size: 24.0,
|
size: 24.0,
|
||||||
color: Colors.black,
|
color:
|
||||||
|
StreamChatTheme.of(context).colorTheme.black,
|
||||||
), () {
|
), () {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
@@ -133,7 +143,10 @@ class ImageActionsModal extends StatelessWidget {
|
|||||||
'Save ${urls[currentIndex].type == 'video' ? 'Video' : 'Image'}',
|
'Save ${urls[currentIndex].type == 'video' ? 'Video' : 'Image'}',
|
||||||
StreamSvgIcon.Icon_save(
|
StreamSvgIcon.Icon_save(
|
||||||
size: 24.0,
|
size: 24.0,
|
||||||
color: Colors.black.withOpacity(0.5),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(0.5),
|
||||||
), () async {
|
), () async {
|
||||||
var url = urls[currentIndex].imageUrl ??
|
var url = urls[currentIndex].imageUrl ??
|
||||||
urls[currentIndex].assetUrl ??
|
urls[currentIndex].assetUrl ??
|
||||||
@@ -153,7 +166,9 @@ class ImageActionsModal extends StatelessWidget {
|
|||||||
'Delete',
|
'Delete',
|
||||||
StreamSvgIcon.delete(
|
StreamSvgIcon.delete(
|
||||||
size: 24.0,
|
size: 24.0,
|
||||||
color: Color(0xffFF3742),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.accentRed,
|
||||||
),
|
),
|
||||||
() {
|
() {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
@@ -163,7 +178,9 @@ class ImageActionsModal extends StatelessWidget {
|
|||||||
StreamChannel.of(context).channel.cid,
|
StreamChannel.of(context).channel.cid,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
color: Color(0xffFF3742),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.accentRed,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
).toList(),
|
).toList(),
|
||||||
@@ -182,10 +199,11 @@ class ImageActionsModal extends StatelessWidget {
|
|||||||
{Color color}) {
|
{Color color}) {
|
||||||
var titleStyle = TextStyle(
|
var titleStyle = TextStyle(
|
||||||
fontSize: 14.5,
|
fontSize: 14.5,
|
||||||
color: Colors.black,
|
color: StreamChatTheme.of(context).colorTheme.black,
|
||||||
);
|
);
|
||||||
|
|
||||||
return Material(
|
return Material(
|
||||||
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
|
|||||||
+124
-118
@@ -5,10 +5,10 @@ import 'dart:typed_data';
|
|||||||
|
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:chewie/chewie.dart';
|
import 'package:chewie/chewie.dart';
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
import 'package:esys_flutter_share/esys_flutter_share.dart';
|
import 'package:esys_flutter_share/esys_flutter_share.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:dio/dio.dart';
|
|
||||||
import 'package:image_gallery_saver/image_gallery_saver.dart';
|
import 'package:image_gallery_saver/image_gallery_saver.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:stream_chat/stream_chat.dart';
|
import 'package:stream_chat/stream_chat.dart';
|
||||||
@@ -16,8 +16,6 @@ import 'package:stream_chat_flutter/src/stream_chat.dart';
|
|||||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
import 'stream_channel.dart';
|
|
||||||
|
|
||||||
class ImageFooter extends StatefulWidget {
|
class ImageFooter extends StatefulWidget {
|
||||||
/// Callback to call when pressing the back button.
|
/// Callback to call when pressing the back button.
|
||||||
/// By default it calls [Navigator.pop]
|
/// By default it calls [Navigator.pop]
|
||||||
@@ -64,11 +62,11 @@ class _ImageFooterState extends State<ImageFooter> {
|
|||||||
bool _userSearchMode = false;
|
bool _userSearchMode = false;
|
||||||
TextEditingController _searchController;
|
TextEditingController _searchController;
|
||||||
TextEditingController _messageController = TextEditingController();
|
TextEditingController _messageController = TextEditingController();
|
||||||
|
FocusNode _messageFocusNode = FocusNode();
|
||||||
|
|
||||||
String _userNameQuery;
|
String _channelNameQuery;
|
||||||
bool _isSearchActive = false;
|
|
||||||
|
|
||||||
Set<User> _selectedUsers = {};
|
List<Channel> _selectedChannels = [];
|
||||||
bool _loading = false;
|
bool _loading = false;
|
||||||
|
|
||||||
Timer _debounce;
|
Timer _debounce;
|
||||||
@@ -80,8 +78,7 @@ class _ImageFooterState extends State<ImageFooter> {
|
|||||||
_debounce = Timer(const Duration(milliseconds: 350), () {
|
_debounce = Timer(const Duration(milliseconds: 350), () {
|
||||||
if (mounted && modalSetStateCallback != null) {
|
if (mounted && modalSetStateCallback != null) {
|
||||||
modalSetStateCallback(() {
|
modalSetStateCallback(() {
|
||||||
_userNameQuery = _searchController.text;
|
_channelNameQuery = _searchController.text;
|
||||||
_isSearchActive = _userNameQuery.isNotEmpty;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -91,6 +88,9 @@ class _ImageFooterState extends State<ImageFooter> {
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_searchController = TextEditingController()..addListener(_userNameListener);
|
_searchController = TextEditingController()..addListener(_userNameListener);
|
||||||
|
_messageFocusNode.addListener(() {
|
||||||
|
setState(() {});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -114,7 +114,7 @@ class _ImageFooterState extends State<ImageFooter> {
|
|||||||
IconButton(
|
IconButton(
|
||||||
icon: StreamSvgIcon.icon_SHARE(
|
icon: StreamSvgIcon.icon_SHARE(
|
||||||
size: 24.0,
|
size: 24.0,
|
||||||
color: Colors.black,
|
color: StreamChatTheme.of(context).colorTheme.black,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
_buildShareModal(context);
|
_buildShareModal(context);
|
||||||
@@ -130,11 +130,7 @@ class _ImageFooterState extends State<ImageFooter> {
|
|||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Text(
|
Text(
|
||||||
'${widget.currentPage + 1} of ${widget.totalPages}',
|
'${widget.currentPage + 1} of ${widget.totalPages}',
|
||||||
style: TextStyle(
|
style: StreamChatTheme.of(context).textTheme.headlineBold,
|
||||||
fontSize: 16.0,
|
|
||||||
fontWeight: FontWeight.w700,
|
|
||||||
color: Colors.black,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -142,7 +138,7 @@ class _ImageFooterState extends State<ImageFooter> {
|
|||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: StreamSvgIcon.Icon_grid(
|
icon: StreamSvgIcon.Icon_grid(
|
||||||
color: Colors.black,
|
color: StreamChatTheme.of(context).colorTheme.black,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
_buildPhotosModal(context);
|
_buildPhotosModal(context);
|
||||||
@@ -170,7 +166,7 @@ class _ImageFooterState extends State<ImageFooter> {
|
|||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white,
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
borderRadius: BorderRadius.only(
|
borderRadius: BorderRadius.only(
|
||||||
topRight: Radius.circular(16.0),
|
topRight: Radius.circular(16.0),
|
||||||
topLeft: Radius.circular(16.0),
|
topLeft: Radius.circular(16.0),
|
||||||
@@ -182,11 +178,8 @@ class _ImageFooterState extends State<ImageFooter> {
|
|||||||
padding: const EdgeInsets.all(16.0),
|
padding: const EdgeInsets.all(16.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
'Photos',
|
'Photos',
|
||||||
style: TextStyle(
|
style:
|
||||||
fontSize: 16.0,
|
StreamChatTheme.of(context).textTheme.headlineBold,
|
||||||
fontWeight: FontWeight.w700,
|
|
||||||
color: Colors.black,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -194,7 +187,7 @@ class _ImageFooterState extends State<ImageFooter> {
|
|||||||
alignment: Alignment.centerRight,
|
alignment: Alignment.centerRight,
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
icon: StreamSvgIcon.close(
|
icon: StreamSvgIcon.close(
|
||||||
color: Colors.black,
|
color: StreamChatTheme.of(context).colorTheme.black,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
@@ -205,7 +198,7 @@ class _ImageFooterState extends State<ImageFooter> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
color: Colors.white,
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
child: GridView.builder(
|
child: GridView.builder(
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
physics: NeverScrollableScrollPhysics(),
|
physics: NeverScrollableScrollPhysics(),
|
||||||
@@ -258,7 +251,7 @@ class _ImageFooterState extends State<ImageFooter> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildShareModal(context) {
|
void _buildShareModal(context) {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
@@ -266,7 +259,7 @@ class _ImageFooterState extends State<ImageFooter> {
|
|||||||
modalSetStateCallback = modalSetState;
|
modalSetStateCallback = modalSetState;
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
top: _userSearchMode
|
top: _userSearchMode || _messageFocusNode.hasFocus
|
||||||
? 16.0
|
? 16.0
|
||||||
: MediaQuery.of(context).size.height / 2,
|
: MediaQuery.of(context).size.height / 2,
|
||||||
left: 8.0,
|
left: 8.0,
|
||||||
@@ -282,80 +275,89 @@ class _ImageFooterState extends State<ImageFooter> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
_buildTextInputSection(modalSetState),
|
_buildTextInputSection(modalSetState),
|
||||||
|
if (_userSearchMode)
|
||||||
|
SizedBox(
|
||||||
|
height: 22.0,
|
||||||
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: UserListView(
|
child: ChannelsBloc(
|
||||||
selectedUsers: _selectedUsers,
|
child: ChannelListView(
|
||||||
onUserTap: (user, _) {
|
selectedChannels: _selectedChannels,
|
||||||
_searchController.clear();
|
onChannelTap: (channel, _) {
|
||||||
if (!_selectedUsers.contains(user)) {
|
_searchController.clear();
|
||||||
modalSetState(() {
|
if (!_selectedChannels.contains(channel)) {
|
||||||
_selectedUsers.add(user);
|
modalSetState(() {
|
||||||
});
|
_selectedChannels.add(channel);
|
||||||
} else {
|
});
|
||||||
modalSetState(() {
|
} else {
|
||||||
_selectedUsers.remove(user);
|
modalSetState(() {
|
||||||
});
|
_selectedChannels.remove(channel);
|
||||||
}
|
});
|
||||||
},
|
}
|
||||||
crossAxisCount: 4,
|
|
||||||
pagination: PaginationParams(
|
|
||||||
limit: 25,
|
|
||||||
),
|
|
||||||
filter: {
|
|
||||||
if (_searchController.text.isNotEmpty)
|
|
||||||
'name': {
|
|
||||||
r'$autocomplete': _userNameQuery,
|
|
||||||
},
|
|
||||||
'id': {
|
|
||||||
r'$ne': StreamChat.of(context).user.id,
|
|
||||||
},
|
},
|
||||||
},
|
crossAxisCount: 4,
|
||||||
sort: [
|
pagination: PaginationParams(
|
||||||
SortOption(
|
limit: 25,
|
||||||
'name',
|
|
||||||
direction: 1,
|
|
||||||
),
|
),
|
||||||
],
|
filter: {
|
||||||
emptyBuilder: (_) {
|
if (_channelNameQuery?.trim()?.isNotEmpty == true)
|
||||||
return LayoutBuilder(
|
'name': {
|
||||||
builder: (context, viewportConstraints) {
|
r'$autocomplete': _channelNameQuery,
|
||||||
return SingleChildScrollView(
|
},
|
||||||
physics: AlwaysScrollableScrollPhysics(),
|
'id': {
|
||||||
child: ConstrainedBox(
|
r'$ne': StreamChat.of(context).user.id,
|
||||||
constraints: BoxConstraints(
|
},
|
||||||
minHeight: viewportConstraints.maxHeight,
|
},
|
||||||
),
|
sort: [
|
||||||
child: Center(
|
SortOption(
|
||||||
child: Column(
|
'name',
|
||||||
children: [
|
direction: SortOption.ASC,
|
||||||
Padding(
|
),
|
||||||
padding: const EdgeInsets.all(24),
|
],
|
||||||
child: StreamSvgIcon.search(
|
emptyBuilder: (_) {
|
||||||
size: 96,
|
return LayoutBuilder(
|
||||||
color: Colors.grey,
|
builder: (context, viewportConstraints) {
|
||||||
|
return SingleChildScrollView(
|
||||||
|
physics: AlwaysScrollableScrollPhysics(),
|
||||||
|
child: ConstrainedBox(
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
minHeight:
|
||||||
|
viewportConstraints.maxHeight,
|
||||||
|
),
|
||||||
|
child: Center(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(24),
|
||||||
|
child: StreamSvgIcon.search(
|
||||||
|
size: 96,
|
||||||
|
color: Colors.grey,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
Text(
|
||||||
Text(
|
'No chat matches these keywords...'),
|
||||||
'No user matches these keywords...'),
|
],
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
);
|
},
|
||||||
},
|
);
|
||||||
);
|
},
|
||||||
},
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (_selectedUsers.isNotEmpty)
|
if (_selectedChannels.isNotEmpty)
|
||||||
_buildShareTextInputSection(modalSetState),
|
_buildShareTextInputSection(modalSetState),
|
||||||
if (!_userSearchMode && _selectedUsers.isEmpty)
|
if (!_userSearchMode && _selectedChannels.isEmpty)
|
||||||
Align(
|
Align(
|
||||||
alignment: Alignment.bottomCenter,
|
alignment: Alignment.bottomCenter,
|
||||||
child: Container(
|
child: Container(
|
||||||
color: Colors.white,
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
height: 48.0,
|
height: 48.0,
|
||||||
child: Material(
|
child: Material(
|
||||||
|
color:
|
||||||
|
StreamChatTheme.of(context).colorTheme.white,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
var url = widget
|
var url = widget
|
||||||
@@ -385,7 +387,8 @@ class _ImageFooterState extends State<ImageFooter> {
|
|||||||
'Save to Photos',
|
'Save to Photos',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: StreamChatTheme.of(context)
|
color: StreamChatTheme.of(context)
|
||||||
.accentColor,
|
.colorTheme
|
||||||
|
.accentBlue,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -422,7 +425,7 @@ class _ImageFooterState extends State<ImageFooter> {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: TextField(
|
child: TextField(
|
||||||
controller: _searchController,
|
controller: _searchController,
|
||||||
cursorColor: Colors.black,
|
cursorColor: StreamChatTheme.of(context).colorTheme.black,
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
isDense: true,
|
isDense: true,
|
||||||
@@ -432,19 +435,25 @@ class _ImageFooterState extends State<ImageFooter> {
|
|||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
vertical: 2.0, horizontal: 6.0),
|
vertical: 2.0, horizontal: 6.0),
|
||||||
child: StreamSvgIcon.search(
|
child: StreamSvgIcon.search(
|
||||||
color: Colors.black,
|
color: StreamChatTheme.of(context).colorTheme.black,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
hintText: 'Search',
|
hintText: 'Search',
|
||||||
border: OutlineInputBorder(
|
border: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(32.0),
|
borderRadius: BorderRadius.circular(32.0),
|
||||||
borderSide:
|
borderSide: BorderSide(
|
||||||
BorderSide(color: Colors.black.withOpacity(0.08)),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(0.08)),
|
||||||
),
|
),
|
||||||
focusedBorder: OutlineInputBorder(
|
focusedBorder: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(32.0),
|
borderRadius: BorderRadius.circular(32.0),
|
||||||
borderSide:
|
borderSide: BorderSide(
|
||||||
BorderSide(color: Colors.black.withOpacity(0.08)),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(0.08)),
|
||||||
),
|
),
|
||||||
contentPadding: EdgeInsets.zero,
|
contentPadding: EdgeInsets.zero,
|
||||||
),
|
),
|
||||||
@@ -455,7 +464,10 @@ class _ImageFooterState extends State<ImageFooter> {
|
|||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: StreamSvgIcon.close_small(
|
icon: StreamSvgIcon.close_small(
|
||||||
color: Colors.black.withOpacity(0.5),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(0.5),
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
modalSetState(() {
|
modalSetState(() {
|
||||||
@@ -476,7 +488,7 @@ class _ImageFooterState extends State<ImageFooter> {
|
|||||||
padding: const EdgeInsets.symmetric(horizontal: 6.0),
|
padding: const EdgeInsets.symmetric(horizontal: 6.0),
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
icon: StreamSvgIcon.search(
|
icon: StreamSvgIcon.search(
|
||||||
color: Colors.black,
|
color: StreamChatTheme.of(context).colorTheme.black,
|
||||||
),
|
),
|
||||||
iconSize: 24.0,
|
iconSize: 24.0,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
@@ -490,18 +502,14 @@ class _ImageFooterState extends State<ImageFooter> {
|
|||||||
padding: const EdgeInsets.all(16.0),
|
padding: const EdgeInsets.all(16.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
'Select a Chat to Share',
|
'Select a Chat to Share',
|
||||||
style: TextStyle(
|
style: StreamChatTheme.of(context).textTheme.headlineBold,
|
||||||
fontSize: 16.0,
|
|
||||||
fontWeight: FontWeight.w700,
|
|
||||||
color: Colors.black,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 6.0),
|
padding: const EdgeInsets.symmetric(horizontal: 6.0),
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
icon: StreamSvgIcon.share_arrow(
|
icon: StreamSvgIcon.share_arrow(
|
||||||
color: Colors.black,
|
color: StreamChatTheme.of(context).colorTheme.black,
|
||||||
),
|
),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
var url =
|
var url =
|
||||||
@@ -528,7 +536,7 @@ class _ImageFooterState extends State<ImageFooter> {
|
|||||||
return Align(
|
return Align(
|
||||||
alignment: Alignment.bottomCenter,
|
alignment: Alignment.bottomCenter,
|
||||||
child: Container(
|
child: Container(
|
||||||
color: Colors.white,
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
height: 56.0,
|
height: 56.0,
|
||||||
child: _loading
|
child: _loading
|
||||||
? Center(
|
? Center(
|
||||||
@@ -544,6 +552,7 @@ class _ImageFooterState extends State<ImageFooter> {
|
|||||||
padding: const EdgeInsets.only(left: 8.0),
|
padding: const EdgeInsets.only(left: 8.0),
|
||||||
child: TextField(
|
child: TextField(
|
||||||
controller: _messageController,
|
controller: _messageController,
|
||||||
|
focusNode: _messageFocusNode,
|
||||||
onChanged: (val) {
|
onChanged: (val) {
|
||||||
modalSetState(() {});
|
modalSetState(() {});
|
||||||
},
|
},
|
||||||
@@ -558,13 +567,19 @@ class _ImageFooterState extends State<ImageFooter> {
|
|||||||
border: OutlineInputBorder(
|
border: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(32.0),
|
borderRadius: BorderRadius.circular(32.0),
|
||||||
borderSide: BorderSide(
|
borderSide: BorderSide(
|
||||||
color: Colors.black.withOpacity(0.16),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(0.16),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
focusedBorder: OutlineInputBorder(
|
focusedBorder: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(32.0),
|
borderRadius: BorderRadius.circular(32.0),
|
||||||
borderSide: BorderSide(
|
borderSide: BorderSide(
|
||||||
color: Colors.black.withOpacity(0.16),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(0.16),
|
||||||
)),
|
)),
|
||||||
contentPadding: EdgeInsets.symmetric(vertical: 12.0),
|
contentPadding: EdgeInsets.symmetric(vertical: 12.0),
|
||||||
),
|
),
|
||||||
@@ -591,7 +606,9 @@ class _ImageFooterState extends State<ImageFooter> {
|
|||||||
child: Transform.rotate(
|
child: Transform.rotate(
|
||||||
angle: -pi / 2,
|
angle: -pi / 2,
|
||||||
child: StreamSvgIcon.Icon_send_message(
|
child: StreamSvgIcon.Icon_send_message(
|
||||||
color: StreamChatTheme.of(context).accentColor,
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.accentBlue,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -612,27 +629,16 @@ class _ImageFooterState extends State<ImageFooter> {
|
|||||||
|
|
||||||
_messageController.clear();
|
_messageController.clear();
|
||||||
|
|
||||||
final client = StreamChat.of(context).client;
|
for (var channel in _selectedChannels) {
|
||||||
|
|
||||||
for (var user in _selectedUsers) {
|
|
||||||
var c = client.channel('messaging', extraData: {
|
|
||||||
'members': [
|
|
||||||
user.id,
|
|
||||||
StreamChat.of(context).user.id,
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
await c.watch();
|
|
||||||
|
|
||||||
final message = Message(
|
final message = Message(
|
||||||
text: text,
|
text: text,
|
||||||
attachments: [attachments[widget.currentPage]],
|
attachments: [attachments[widget.currentPage]],
|
||||||
);
|
);
|
||||||
|
|
||||||
await c.sendMessage(message);
|
await channel.sendMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
_selectedUsers.clear();
|
_selectedChannels.clear();
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -83,7 +83,9 @@ class ImageGroup extends StatelessWidget {
|
|||||||
child: Text(
|
child: Text(
|
||||||
'${images.length - 4} +',
|
'${images.length - 4} +',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.white,
|
||||||
fontSize: 28,
|
fontSize: 28,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
leading: showBackButton
|
leading: showBackButton
|
||||||
? IconButton(
|
? IconButton(
|
||||||
icon: StreamSvgIcon.close(
|
icon: StreamSvgIcon.close(
|
||||||
color: Colors.black,
|
color: StreamChatTheme.of(context).colorTheme.black,
|
||||||
size: 24.0,
|
size: 24.0,
|
||||||
),
|
),
|
||||||
onPressed: onBackPressed,
|
onPressed: onBackPressed,
|
||||||
@@ -61,7 +61,7 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
actions: <Widget>[
|
actions: <Widget>[
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: StreamSvgIcon.Icon_menu_point_v(
|
icon: StreamSvgIcon.Icon_menu_point_v(
|
||||||
color: Colors.black,
|
color: StreamChatTheme.of(context).colorTheme.black,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
_showMessageActionModalBottomSheet(context);
|
_showMessageActionModalBottomSheet(context);
|
||||||
@@ -81,11 +81,7 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Text(
|
Text(
|
||||||
userName,
|
userName,
|
||||||
style: TextStyle(
|
style: StreamChatTheme.of(context).textTheme.headlineBold,
|
||||||
fontSize: 16.0,
|
|
||||||
fontWeight: FontWeight.w700,
|
|
||||||
color: Colors.black,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
sentAt,
|
sentAt,
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
|
import 'dart:ui' as ui;
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:photo_manager/photo_manager.dart';
|
import 'package:photo_manager/photo_manager.dart';
|
||||||
import 'package:stream_chat_flutter/src/lazy_load_scroll_view.dart';
|
import 'package:stream_chat_flutter/src/lazy_load_scroll_view.dart';
|
||||||
import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
|
import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
|
||||||
import 'dart:ui' as ui;
|
|
||||||
|
import '../stream_chat_flutter.dart';
|
||||||
|
|
||||||
extension on Duration {
|
extension on Duration {
|
||||||
String format() {
|
String format() {
|
||||||
@@ -80,7 +83,10 @@ class _MediaListViewState extends State<MediaListView> {
|
|||||||
? 1.0
|
? 1.0
|
||||||
: 0.0,
|
: 0.0,
|
||||||
child: Container(
|
child: Container(
|
||||||
color: Colors.black.withOpacity(0.5),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(0.5),
|
||||||
alignment: Alignment.topRight,
|
alignment: Alignment.topRight,
|
||||||
padding: const EdgeInsets.only(
|
padding: const EdgeInsets.only(
|
||||||
top: 8,
|
top: 8,
|
||||||
@@ -88,10 +94,12 @@ class _MediaListViewState extends State<MediaListView> {
|
|||||||
),
|
),
|
||||||
child: CircleAvatar(
|
child: CircleAvatar(
|
||||||
radius: 12,
|
radius: 12,
|
||||||
backgroundColor: Colors.white,
|
backgroundColor:
|
||||||
|
StreamChatTheme.of(context).colorTheme.white,
|
||||||
child: StreamSvgIcon.check(
|
child: StreamSvgIcon.check(
|
||||||
size: 24,
|
size: 24,
|
||||||
color: Colors.black,
|
color:
|
||||||
|
StreamChatTheme.of(context).colorTheme.black,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -113,7 +121,7 @@ class _MediaListViewState extends State<MediaListView> {
|
|||||||
child: Text(
|
child: Text(
|
||||||
media.videoDuration.format(),
|
media.videoDuration.format(),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -141,7 +149,15 @@ class _MediaListViewState extends State<MediaListView> {
|
|||||||
void _getMedia() async {
|
void _getMedia() async {
|
||||||
final assetList = await PhotoManager.getAssetPathList(
|
final assetList = await PhotoManager.getAssetPathList(
|
||||||
hasAll: true,
|
hasAll: true,
|
||||||
).then((value) => value.singleWhere((element) => element.isAll));
|
).then((value) {
|
||||||
|
if (value?.isNotEmpty == true) {
|
||||||
|
return value.singleWhere((element) => element.isAll);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (assetList == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final media = await assetList.getAssetListPaged(_currentPage, 50);
|
final media = await assetList.getAssetListPaged(_currentPage, 50);
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ class MessageActionsModal extends StatelessWidget {
|
|||||||
final bool showDeleteMessage;
|
final bool showDeleteMessage;
|
||||||
final bool showCopyMessage;
|
final bool showCopyMessage;
|
||||||
final bool showEditMessage;
|
final bool showEditMessage;
|
||||||
|
final bool showResendMessage;
|
||||||
final bool showReply;
|
final bool showReply;
|
||||||
final bool showThreadReply;
|
final bool showThreadReply;
|
||||||
final bool reverse;
|
final bool reverse;
|
||||||
@@ -40,6 +41,7 @@ class MessageActionsModal extends StatelessWidget {
|
|||||||
this.onThreadReplyTap,
|
this.onThreadReplyTap,
|
||||||
this.showCopyMessage = true,
|
this.showCopyMessage = true,
|
||||||
this.showReply = true,
|
this.showReply = true,
|
||||||
|
this.showResendMessage = true,
|
||||||
this.showThreadReply = true,
|
this.showThreadReply = true,
|
||||||
this.showUserAvatar = DisplayWidget.show,
|
this.showUserAvatar = DisplayWidget.show,
|
||||||
this.editMessageInputBuilder,
|
this.editMessageInputBuilder,
|
||||||
@@ -73,7 +75,7 @@ class MessageActionsModal extends StatelessWidget {
|
|||||||
sigmaY: 10.8731,
|
sigmaY: 10.8731,
|
||||||
),
|
),
|
||||||
child: Container(
|
child: Container(
|
||||||
color: Colors.black.withOpacity(0.1),
|
color: Colors.black.withOpacity(.2),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -122,7 +124,10 @@ class MessageActionsModal extends StatelessWidget {
|
|||||||
showUserAvatar: showUserAvatar,
|
showUserAvatar: showUserAvatar,
|
||||||
showTimestamp: false,
|
showTimestamp: false,
|
||||||
translateUserAvatar: false,
|
translateUserAvatar: false,
|
||||||
showReactionPickerIndicator: true,
|
showReactionPickerIndicator: showReactions &&
|
||||||
|
(message.status ==
|
||||||
|
MessageSendingStatus.SENT ||
|
||||||
|
message.status == null),
|
||||||
showInChannelIndicator: false,
|
showInChannelIndicator: false,
|
||||||
showSendingIndicator: DisplayWidget.gone,
|
showSendingIndicator: DisplayWidget.gone,
|
||||||
shape: messageShape,
|
shape: messageShape,
|
||||||
@@ -130,9 +135,7 @@ class MessageActionsModal extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
SizedBox(
|
SizedBox(height: 8),
|
||||||
height: 8,
|
|
||||||
),
|
|
||||||
TweenAnimationBuilder<double>(
|
TweenAnimationBuilder<double>(
|
||||||
tween: Tween(begin: 0.0, end: 1.0),
|
tween: Tween(begin: 0.0, end: 1.0),
|
||||||
duration: Duration(milliseconds: 300),
|
duration: Duration(milliseconds: 300),
|
||||||
@@ -148,6 +151,9 @@ class MessageActionsModal extends StatelessWidget {
|
|||||||
horizontal: 48.0,
|
horizontal: 48.0,
|
||||||
),
|
),
|
||||||
child: Material(
|
child: Material(
|
||||||
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.whiteSnow,
|
||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.hardEdge,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius: BorderRadius.circular(16),
|
||||||
@@ -166,10 +172,12 @@ class MessageActionsModal extends StatelessWidget {
|
|||||||
_buildReplyButton(context),
|
_buildReplyButton(context),
|
||||||
if (showThreadReply &&
|
if (showThreadReply &&
|
||||||
(message.status ==
|
(message.status ==
|
||||||
MessageSendingStatus.SENT ||
|
MessageSendingStatus.SENT ||
|
||||||
message.status == null) &&
|
message.status == null) &&
|
||||||
message.parentId == null)
|
message.parentId == null)
|
||||||
_buildThreadReplyButton(context),
|
_buildThreadReplyButton(context),
|
||||||
|
if (showResendMessage)
|
||||||
|
_buildResendMessage(context),
|
||||||
if (showEditMessage)
|
if (showEditMessage)
|
||||||
_buildEditMessage(context),
|
_buildEditMessage(context),
|
||||||
if (showDeleteMessage)
|
if (showDeleteMessage)
|
||||||
@@ -212,9 +220,10 @@ class MessageActionsModal extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildDeleteButton(BuildContext context) {
|
Widget _buildDeleteButton(BuildContext context) {
|
||||||
|
final isDeleteFailed = message.status == MessageSendingStatus.FAILED_DELETE;
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text(
|
title: Text(
|
||||||
'Delete message',
|
isDeleteFailed ? 'Retry deleting message' : 'Delete message',
|
||||||
style:
|
style:
|
||||||
Theme.of(context).textTheme.headline6.copyWith(color: Colors.red),
|
Theme.of(context).textTheme.headline6.copyWith(color: Colors.red),
|
||||||
),
|
),
|
||||||
@@ -263,6 +272,29 @@ class MessageActionsModal extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildResendMessage(BuildContext context) {
|
||||||
|
final isUpdateFailed = message.status == MessageSendingStatus.FAILED_UPDATE;
|
||||||
|
return ListTile(
|
||||||
|
title: Text(
|
||||||
|
isUpdateFailed ? 'Resend edited message' : 'Resend',
|
||||||
|
style: Theme.of(context).textTheme.headline6,
|
||||||
|
),
|
||||||
|
leading: StreamSvgIcon.circle_up(
|
||||||
|
color: StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
final client = StreamChat.of(context).client;
|
||||||
|
final channel = StreamChannel.of(context).channel;
|
||||||
|
if (isUpdateFailed) {
|
||||||
|
client.updateMessage(message, channel.cid);
|
||||||
|
} else {
|
||||||
|
channel.sendMessage(message);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void _showEditBottomSheet(BuildContext context) {
|
void _showEditBottomSheet(BuildContext context) {
|
||||||
final channel = StreamChannel.of(context).channel;
|
final channel = StreamChannel.of(context).channel;
|
||||||
showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
@@ -270,6 +302,7 @@ class MessageActionsModal extends StatelessWidget {
|
|||||||
elevation: 2,
|
elevation: 2,
|
||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.hardEdge,
|
||||||
isScrollControlled: true,
|
isScrollControlled: true,
|
||||||
|
backgroundColor: StreamChatTheme.of(context).colorTheme.white,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.only(
|
borderRadius: BorderRadius.only(
|
||||||
topLeft: Radius.circular(32),
|
topLeft: Radius.circular(32),
|
||||||
@@ -330,9 +363,10 @@ class MessageActionsModal extends StatelessWidget {
|
|||||||
? editMessageInputBuilder(context, message)
|
? editMessageInputBuilder(context, message)
|
||||||
: MessageInput(
|
: MessageInput(
|
||||||
editMessage: message,
|
editMessage: message,
|
||||||
onMessageSent: (_) {
|
preMessageSending: (m) {
|
||||||
FocusScope.of(context).unfocus();
|
FocusScope.of(context).unfocus();
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
|
return m;
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
+97
-69
@@ -305,7 +305,10 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
border: _sendAsDm
|
border: _sendAsDm
|
||||||
? null
|
? null
|
||||||
: Border.all(
|
: Border.all(
|
||||||
color: Colors.black.withOpacity(.5),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(.5),
|
||||||
width: 2,
|
width: 2,
|
||||||
),
|
),
|
||||||
borderRadius: BorderRadius.circular(3),
|
borderRadius: BorderRadius.circular(3),
|
||||||
@@ -314,8 +317,8 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
child: Material(
|
child: Material(
|
||||||
borderRadius: BorderRadius.circular(3),
|
borderRadius: BorderRadius.circular(3),
|
||||||
color: _sendAsDm
|
color: _sendAsDm
|
||||||
? StreamChatTheme.of(context).accentColor
|
? StreamChatTheme.of(context).colorTheme.accentBlue
|
||||||
: Colors.white,
|
: StreamChatTheme.of(context).colorTheme.white,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
@@ -330,7 +333,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
: CrossFadeState.showSecond,
|
: CrossFadeState.showSecond,
|
||||||
firstChild: StreamSvgIcon.check(
|
firstChild: StreamSvgIcon.check(
|
||||||
size: 16.0,
|
size: 16.0,
|
||||||
color: Colors.white,
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
),
|
),
|
||||||
secondChild: SizedBox(
|
secondChild: SizedBox(
|
||||||
height: 16,
|
height: 16,
|
||||||
@@ -376,7 +379,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
icon: StreamSvgIcon.emptyCircleLeft(
|
icon: StreamSvgIcon.emptyCircleLeft(
|
||||||
color: StreamChatTheme.of(context).accentColor,
|
color: StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||||
),
|
),
|
||||||
padding: const EdgeInsets.all(0),
|
padding: const EdgeInsets.all(0),
|
||||||
constraints: BoxConstraints.tightFor(
|
constraints: BoxConstraints.tightFor(
|
||||||
@@ -409,7 +412,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(24.0),
|
borderRadius: BorderRadius.circular(24.0),
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: Colors.black.withOpacity(0.16),
|
color: StreamChatTheme.of(context).colorTheme.greyGainsboro,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
padding: _attachments.isEmpty ? null : EdgeInsets.all(6.0),
|
padding: _attachments.isEmpty ? null : EdgeInsets.all(6.0),
|
||||||
@@ -458,8 +461,9 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
padding:
|
padding:
|
||||||
const EdgeInsets.symmetric(horizontal: 8.0),
|
const EdgeInsets.symmetric(horizontal: 8.0),
|
||||||
child: Chip(
|
child: Chip(
|
||||||
backgroundColor:
|
backgroundColor: StreamChatTheme.of(context)
|
||||||
StreamChatTheme.of(context).accentColor,
|
.colorTheme
|
||||||
|
.accentBlue,
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
labelPadding:
|
labelPadding:
|
||||||
EdgeInsets.symmetric(horizontal: 8.0),
|
EdgeInsets.symmetric(horizontal: 8.0),
|
||||||
@@ -468,13 +472,20 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
StreamSvgIcon.lightning(
|
StreamSvgIcon.lightning(
|
||||||
color: Colors.white,
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.white,
|
||||||
size: 16.0,
|
size: 16.0,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
_chosenCommand?.name?.toUpperCase() ?? '',
|
_chosenCommand?.name?.toUpperCase() ?? '',
|
||||||
style: TextStyle(
|
style: StreamChatTheme.of(context)
|
||||||
color: Colors.white, fontSize: 12.0),
|
.textTheme
|
||||||
|
.footnote
|
||||||
|
.copyWith(
|
||||||
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.white),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -643,12 +654,12 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(8.0),
|
borderRadius: BorderRadius.circular(8.0),
|
||||||
),
|
),
|
||||||
color: StreamChatTheme.of(context).primaryColor,
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
clipBehavior: Clip.antiAlias,
|
clipBehavior: Clip.antiAlias,
|
||||||
child: Container(
|
child: Container(
|
||||||
constraints: BoxConstraints.loose(Size.fromHeight(400)),
|
constraints: BoxConstraints.loose(Size.fromHeight(400)),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: StreamChatTheme.of(context).primaryColor,
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
borderRadius: BorderRadius.circular(8.0)),
|
borderRadius: BorderRadius.circular(8.0)),
|
||||||
child: ListView(
|
child: ListView(
|
||||||
padding: const EdgeInsets.all(0),
|
padding: const EdgeInsets.all(0),
|
||||||
@@ -666,13 +677,17 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
),
|
),
|
||||||
child: StreamSvgIcon.lightning(
|
child: StreamSvgIcon.lightning(
|
||||||
color: StreamChatTheme.of(context)
|
color: StreamChatTheme.of(context)
|
||||||
.accentColor,
|
.colorTheme
|
||||||
|
.accentBlue,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'Instant Commands',
|
'Instant Commands',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.black.withOpacity(.5),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(.5),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
@@ -699,15 +714,6 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
trailing: CircleAvatar(
|
|
||||||
backgroundColor:
|
|
||||||
StreamChatTheme.of(context).accentColor,
|
|
||||||
child: StreamSvgIcon.lightning(
|
|
||||||
color: Colors.white,
|
|
||||||
size: 12.5,
|
|
||||||
),
|
|
||||||
maxRadius: 12,
|
|
||||||
),
|
|
||||||
//subtitle: Text(c.description),
|
//subtitle: Text(c.description),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
_setCommand(c);
|
_setCommand(c);
|
||||||
@@ -734,27 +740,36 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
switch (index) {
|
switch (index) {
|
||||||
case 0:
|
case 0:
|
||||||
return _attachments.isEmpty
|
return _attachments.isEmpty
|
||||||
? StreamChatTheme.of(context).accentColor
|
? StreamChatTheme.of(context).colorTheme.accentBlue
|
||||||
: (!_attachmentContainsFile
|
: (!_attachmentContainsFile
|
||||||
? StreamChatTheme.of(context).accentColor
|
? StreamChatTheme.of(context).colorTheme.accentBlue
|
||||||
: Colors.black.withOpacity(0.2));
|
: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(0.2));
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
return _attachmentContainsFile
|
return _attachmentContainsFile
|
||||||
? StreamChatTheme.of(context).accentColor
|
? StreamChatTheme.of(context).colorTheme.accentBlue
|
||||||
: (_attachments.isEmpty
|
: (_attachments.isEmpty
|
||||||
? Colors.black.withOpacity(0.5)
|
? StreamChatTheme.of(context)
|
||||||
: Colors.black.withOpacity(0.2));
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(0.5)
|
||||||
|
: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(0.2));
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
return _attachmentContainsFile && _attachments.isNotEmpty
|
return _attachmentContainsFile && _attachments.isNotEmpty
|
||||||
? Colors.black.withOpacity(0.2)
|
? StreamChatTheme.of(context).colorTheme.black.withOpacity(0.2)
|
||||||
: Colors.black.withOpacity(0.5);
|
: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
return _attachmentContainsFile && _attachments.isNotEmpty
|
return _attachmentContainsFile && _attachments.isNotEmpty
|
||||||
? Colors.black.withOpacity(0.2)
|
? StreamChatTheme.of(context).colorTheme.black.withOpacity(0.2)
|
||||||
: Colors.black.withOpacity(0.5);
|
: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -763,7 +778,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
duration: _animateContainer ? Duration(milliseconds: 300) : Duration.zero,
|
duration: _animateContainer ? Duration(milliseconds: 300) : Duration.zero,
|
||||||
height: _openFilePickerSection ? _filePickerSize : 0,
|
height: _openFilePickerSection ? _filePickerSize : 0,
|
||||||
child: Material(
|
child: Material(
|
||||||
color: Color(0xFFF2F2F2),
|
color: StreamChatTheme.of(context).colorTheme.whiteSmoke,
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
@@ -830,7 +845,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white,
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
borderRadius: BorderRadius.only(
|
borderRadius: BorderRadius.only(
|
||||||
topLeft: Radius.circular(16.0),
|
topLeft: Radius.circular(16.0),
|
||||||
topRight: Radius.circular(16.0),
|
topRight: Radius.circular(16.0),
|
||||||
@@ -845,7 +860,8 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
width: 40.0,
|
width: 40.0,
|
||||||
height: 4.0,
|
height: 4.0,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Color(0xFFF2F2F2),
|
color:
|
||||||
|
StreamChatTheme.of(context).colorTheme.whiteSmoke,
|
||||||
borderRadius: BorderRadius.circular(4.0),
|
borderRadius: BorderRadius.circular(4.0),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -858,7 +874,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white,
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
borderRadius: BorderRadius.circular(8.0),
|
borderRadius: BorderRadius.circular(8.0),
|
||||||
),
|
),
|
||||||
child: _buildPickerSection(),
|
child: _buildPickerSection(),
|
||||||
@@ -893,11 +909,12 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
constraints: BoxConstraints.expand(),
|
constraints: BoxConstraints.expand(),
|
||||||
color: Color(0xfff2f2f2),
|
color: StreamChatTheme.of(context).colorTheme.whiteSmoke,
|
||||||
child: Text(
|
child: Text(
|
||||||
'Add more files',
|
'Add more files',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: StreamChatTheme.of(context).accentColor,
|
color:
|
||||||
|
StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -926,7 +943,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
PhotoManager.openSetting();
|
PhotoManager.openSetting();
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
color: Color(0xFFF2F2F2),
|
color: StreamChatTheme.of(context).colorTheme.whiteSmoke,
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
@@ -935,16 +952,20 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
'svgs/icon_picture_empty_state.svg',
|
'svgs/icon_picture_empty_state.svg',
|
||||||
package: 'stream_chat_flutter',
|
package: 'stream_chat_flutter',
|
||||||
height: 140,
|
height: 140,
|
||||||
color: StreamChatTheme.of(context).accentColor,
|
color:
|
||||||
|
StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||||
),
|
),
|
||||||
Center(
|
Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
'Allow access to your gallery',
|
'Allow access to your gallery',
|
||||||
style: TextStyle(
|
style: StreamChatTheme.of(context)
|
||||||
fontSize: 14,
|
.textTheme
|
||||||
fontWeight: FontWeight.bold,
|
.bodyBold
|
||||||
color: StreamChatTheme.of(context).accentColor,
|
.copyWith(
|
||||||
),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.accentBlue,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -1060,7 +1081,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
CircleAvatar _buildGiphyIcon() {
|
CircleAvatar _buildGiphyIcon() {
|
||||||
if (kIsWeb) {
|
if (kIsWeb) {
|
||||||
return CircleAvatar(
|
return CircleAvatar(
|
||||||
backgroundColor: Colors.black,
|
backgroundColor: StreamChatTheme.of(context).colorTheme.black,
|
||||||
child: Image.asset(
|
child: Image.asset(
|
||||||
'images/giphy_icon.png',
|
'images/giphy_icon.png',
|
||||||
package: 'stream_chat_flutter',
|
package: 'stream_chat_flutter',
|
||||||
@@ -1121,7 +1142,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
child: Card(
|
child: Card(
|
||||||
margin: EdgeInsets.all(8.0),
|
margin: EdgeInsets.all(8.0),
|
||||||
elevation: 2.0,
|
elevation: 2.0,
|
||||||
color: StreamChatTheme.of(context).primaryColor,
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(8.0),
|
borderRadius: BorderRadius.circular(8.0),
|
||||||
),
|
),
|
||||||
@@ -1129,7 +1150,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
child: Container(
|
child: Container(
|
||||||
constraints: BoxConstraints.loose(Size.fromHeight(400)),
|
constraints: BoxConstraints.loose(Size.fromHeight(400)),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: StreamChatTheme.of(context).primaryColor,
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
),
|
),
|
||||||
child: FutureBuilder<List<Member>>(
|
child: FutureBuilder<List<Member>>(
|
||||||
future: queryMembers ?? Future.value(members),
|
future: queryMembers ?? Future.value(members),
|
||||||
@@ -1157,7 +1178,8 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
subtitle: Text('@${m.userId}'),
|
subtitle: Text('@${m.userId}'),
|
||||||
trailing: StreamSvgIcon.mentions(
|
trailing: StreamSvgIcon.mentions(
|
||||||
color: StreamChatTheme.of(context)
|
color: StreamChatTheme.of(context)
|
||||||
.accentColor,
|
.colorTheme
|
||||||
|
.accentBlue,
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
_mentionedUsers.add(m.user);
|
_mentionedUsers.add(m.user);
|
||||||
@@ -1222,7 +1244,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
child: Card(
|
child: Card(
|
||||||
margin: EdgeInsets.all(8.0),
|
margin: EdgeInsets.all(8.0),
|
||||||
elevation: 2.0,
|
elevation: 2.0,
|
||||||
color: StreamChatTheme.of(context).primaryColor,
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(8.0),
|
borderRadius: BorderRadius.circular(8.0),
|
||||||
),
|
),
|
||||||
@@ -1237,7 +1259,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
offset: Offset(0, -4),
|
offset: Offset(0, -4),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
color: StreamChatTheme.of(context).primaryColor,
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
),
|
),
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
padding: const EdgeInsets.all(0),
|
padding: const EdgeInsets.all(0),
|
||||||
@@ -1253,14 +1275,19 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
padding:
|
padding:
|
||||||
const EdgeInsets.symmetric(horizontal: 8.0),
|
const EdgeInsets.symmetric(horizontal: 8.0),
|
||||||
child: StreamSvgIcon.smile(
|
child: StreamSvgIcon.smile(
|
||||||
color: StreamChatTheme.of(context).accentColor,
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.accentBlue,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Flexible(
|
Flexible(
|
||||||
child: Text(
|
child: Text(
|
||||||
'Emoji matching "$query"',
|
'Emoji matching "$query"',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.black.withOpacity(.5),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(.5),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -1373,10 +1400,15 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
child: InkWell(
|
child: InkWell(
|
||||||
child: CircleAvatar(
|
child: CircleAvatar(
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
Colors.black.withOpacity(0.2),
|
StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(0.6),
|
||||||
maxRadius: 12.0,
|
maxRadius: 12.0,
|
||||||
child: StreamSvgIcon.close(
|
child: StreamSvgIcon.close(
|
||||||
color: Colors.white,
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.white,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
@@ -1461,11 +1493,11 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
_attachments.remove(attachment);
|
_attachments.remove(attachment);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
fillColor: Colors.black.withOpacity(.5),
|
fillColor: StreamChatTheme.of(context).colorTheme.black.withOpacity(.5),
|
||||||
child: Center(
|
child: Center(
|
||||||
child: StreamSvgIcon.close(
|
child: StreamSvgIcon.close(
|
||||||
size: 24,
|
size: 24,
|
||||||
color: Colors.white,
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -1553,8 +1585,8 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
child: IconButton(
|
child: IconButton(
|
||||||
icon: StreamSvgIcon.lightning(
|
icon: StreamSvgIcon.lightning(
|
||||||
color: _commandsOverlay != null
|
color: _commandsOverlay != null
|
||||||
? StreamChatTheme.of(context).accentColor
|
? StreamChatTheme.of(context).colorTheme.accentBlue
|
||||||
: Color(0xFF000000).withAlpha(128),
|
: StreamChatTheme.of(context).colorTheme.grey,
|
||||||
),
|
),
|
||||||
padding: const EdgeInsets.all(0),
|
padding: const EdgeInsets.all(0),
|
||||||
constraints: BoxConstraints.tightFor(
|
constraints: BoxConstraints.tightFor(
|
||||||
@@ -1594,8 +1626,8 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
child: IconButton(
|
child: IconButton(
|
||||||
icon: StreamSvgIcon.attach(
|
icon: StreamSvgIcon.attach(
|
||||||
color: _openFilePickerSection
|
color: _openFilePickerSection
|
||||||
? StreamChatTheme.of(context).accentColor
|
? StreamChatTheme.of(context).colorTheme.accentBlue
|
||||||
: Color(0xFF000000).withAlpha(128),
|
: StreamChatTheme.of(context).colorTheme.grey,
|
||||||
),
|
),
|
||||||
padding: const EdgeInsets.all(0),
|
padding: const EdgeInsets.all(0),
|
||||||
constraints: BoxConstraints.tightFor(
|
constraints: BoxConstraints.tightFor(
|
||||||
@@ -1924,7 +1956,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 8),
|
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 8),
|
||||||
child: StreamSvgIcon(
|
child: StreamSvgIcon(
|
||||||
assetName: _getIdleSendIcon(),
|
assetName: _getIdleSendIcon(),
|
||||||
color: Colors.grey,
|
color: StreamChatTheme.of(context).colorTheme.greyGainsboro,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1943,7 +1975,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
),
|
),
|
||||||
icon: StreamSvgIcon(
|
icon: StreamSvgIcon(
|
||||||
assetName: _getSendIcon(),
|
assetName: _getSendIcon(),
|
||||||
color: StreamChatTheme.of(context).accentColor,
|
color: StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -2043,10 +2075,6 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
return sendingFuture.then((resp) {
|
return sendingFuture.then((resp) {
|
||||||
if (widget.onMessageSent != null) {
|
if (widget.onMessageSent != null) {
|
||||||
widget.onMessageSent(resp.message);
|
widget.onMessageSent(resp.message);
|
||||||
} else {
|
|
||||||
if (widget.editMessage != null) {
|
|
||||||
Navigator.pop(context);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -259,16 +259,19 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final messageList = snapshot.data?.reversed?.toList() ?? [];
|
final messageList = snapshot.data?.reversed?.toList() ?? [];
|
||||||
|
|
||||||
if (messageList.isEmpty) {
|
if (messageList.isEmpty) {
|
||||||
if (_upToDate) {
|
if (_upToDate) {
|
||||||
return Center(
|
return Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
'No chats here yet...',
|
'No chats here yet...',
|
||||||
style: TextStyle(
|
style: StreamChatTheme.of(context)
|
||||||
fontSize: 12,
|
.textTheme
|
||||||
color: Colors.black.withOpacity(.5),
|
.footnote
|
||||||
),
|
.copyWith(
|
||||||
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(.5)),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -355,8 +358,12 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
begin: Alignment.topCenter,
|
begin: Alignment.topCenter,
|
||||||
end: Alignment.bottomCenter,
|
end: Alignment.bottomCenter,
|
||||||
colors: [
|
colors: [
|
||||||
Color(0XFFF7F7F7),
|
StreamChatTheme.of(context)
|
||||||
Color(0XFFFCFCFC),
|
.colorTheme
|
||||||
|
.whiteSmoke,
|
||||||
|
StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.whiteSnow,
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -536,9 +543,9 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
clipBehavior: Clip.none,
|
clipBehavior: Clip.none,
|
||||||
children: [
|
children: [
|
||||||
FloatingActionButton(
|
FloatingActionButton(
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: StreamChatTheme.of(context).colorTheme.white,
|
||||||
child: StreamSvgIcon.down(
|
child: StreamSvgIcon.down(
|
||||||
color: Colors.black,
|
color: StreamChatTheme.of(context).colorTheme.black,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (unreadCount > 0) {
|
if (unreadCount > 0) {
|
||||||
@@ -598,7 +605,10 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
if (snapshot.hasError) {
|
if (snapshot.hasError) {
|
||||||
return Container(
|
return Container(
|
||||||
color: Color(0xffd0021B).withAlpha(26),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.accentRed
|
||||||
|
.withOpacity(.2),
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Text('Error loading messages'),
|
child: Text('Error loading messages'),
|
||||||
),
|
),
|
||||||
@@ -867,7 +877,7 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
}
|
}
|
||||||
if (event.message.user.id == streamChannel.channel.client.state.user.id) {
|
if (event.message.user.id == streamChannel.channel.client.state.user.id) {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
_scrollController.jumpTo(
|
_scrollController?.jumpTo(
|
||||||
index: 0,
|
index: 0,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ class MessageReactionsModal extends StatelessWidget {
|
|||||||
sigmaY: 10.8731,
|
sigmaY: 10.8731,
|
||||||
),
|
),
|
||||||
child: Container(
|
child: Container(
|
||||||
color: Colors.black.withOpacity(0.1),
|
color: Colors.black.withOpacity(0.2),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -110,14 +110,16 @@ class MessageReactionsModal extends StatelessWidget {
|
|||||||
translateUserAvatar: false,
|
translateUserAvatar: false,
|
||||||
showSendingIndicator: DisplayWidget.gone,
|
showSendingIndicator: DisplayWidget.gone,
|
||||||
shape: messageShape,
|
shape: messageShape,
|
||||||
showReactionPickerIndicator: true,
|
showInChannelIndicator: false,
|
||||||
|
showReactionPickerIndicator: showReactions &&
|
||||||
|
(message.status ==
|
||||||
|
MessageSendingStatus.SENT ||
|
||||||
|
message.status == null),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
SizedBox(
|
SizedBox(height: 8),
|
||||||
height: 16,
|
|
||||||
),
|
|
||||||
if (message.latestReactions?.isNotEmpty == true)
|
if (message.latestReactions?.isNotEmpty == true)
|
||||||
_buildReactionCard(context),
|
_buildReactionCard(context),
|
||||||
],
|
],
|
||||||
@@ -137,6 +139,7 @@ class MessageReactionsModal extends StatelessWidget {
|
|||||||
horizontal: 8.0,
|
horizontal: 8.0,
|
||||||
),
|
),
|
||||||
child: Card(
|
child: Card(
|
||||||
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.hardEdge,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
|||||||
@@ -126,8 +126,6 @@ class MessageSearchItem extends StatelessWidget {
|
|||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: StreamChatTheme.of(context).channelPreviewTheme.subtitle.copyWith(
|
style: StreamChatTheme.of(context).channelPreviewTheme.subtitle.copyWith(
|
||||||
color:
|
|
||||||
StreamChatTheme.of(context).channelPreviewTheme.subtitle.color,
|
|
||||||
fontStyle: (message.isSystem || message.isDeleted)
|
fontStyle: (message.isSystem || message.isDeleted)
|
||||||
? FontStyle.italic
|
? FontStyle.italic
|
||||||
: FontStyle.normal,
|
: FontStyle.normal,
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:stream_chat/stream_chat.dart';
|
import 'package:stream_chat/stream_chat.dart';
|
||||||
import 'package:stream_chat_flutter/src/message_search_item.dart';
|
import 'package:stream_chat_flutter/src/message_search_item.dart';
|
||||||
|
|
||||||
|
import '../stream_chat_flutter.dart';
|
||||||
import 'lazy_load_scroll_view.dart';
|
import 'lazy_load_scroll_view.dart';
|
||||||
import 'message_search_bloc.dart';
|
import 'message_search_bloc.dart';
|
||||||
|
|
||||||
@@ -127,8 +128,8 @@ class _MessageSearchListViewState extends State<MessageSearchListView> {
|
|||||||
return Container(
|
return Container(
|
||||||
height: 1,
|
height: 1,
|
||||||
color: Theme.of(context).brightness == Brightness.dark
|
color: Theme.of(context).brightness == Brightness.dark
|
||||||
? Colors.white.withOpacity(0.1)
|
? StreamChatTheme.of(context).colorTheme.white.withOpacity(0.1)
|
||||||
: Colors.black.withOpacity(0.1),
|
: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.1),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,7 +152,10 @@ class _MessageSearchListViewState extends State<MessageSearchListView> {
|
|||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
if (snapshot.hasError) {
|
if (snapshot.hasError) {
|
||||||
return Container(
|
return Container(
|
||||||
color: Color(0xffd0021B).withAlpha(26),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.accentRed
|
||||||
|
.withOpacity(.2),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||||
child: Center(
|
child: Center(
|
||||||
@@ -313,8 +317,14 @@ class _MessageSearchListViewState extends State<MessageSearchListView> {
|
|||||||
begin: Alignment.centerLeft,
|
begin: Alignment.centerLeft,
|
||||||
end: Alignment.centerRight,
|
end: Alignment.centerRight,
|
||||||
colors: [
|
colors: [
|
||||||
Colors.black.withOpacity(0.02),
|
StreamChatTheme.of(context)
|
||||||
Colors.white.withOpacity(0.05),
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(0.02),
|
||||||
|
StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.white
|
||||||
|
.withOpacity(0.05),
|
||||||
],
|
],
|
||||||
stops: [0, 1],
|
stops: [0, 1],
|
||||||
),
|
),
|
||||||
@@ -327,7 +337,10 @@ class _MessageSearchListViewState extends State<MessageSearchListView> {
|
|||||||
child: Text(
|
child: Text(
|
||||||
'${items.length} results',
|
'${items.length} results',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.black.withOpacity(0.5),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(0.5),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
+193
-223
@@ -120,6 +120,9 @@ class MessageWidget extends StatefulWidget {
|
|||||||
/// Used in [MessageReactionsModal] and [MessageActionsModal]
|
/// Used in [MessageReactionsModal] and [MessageActionsModal]
|
||||||
final bool showReactionPickerIndicator;
|
final bool showReactionPickerIndicator;
|
||||||
|
|
||||||
|
/// If true the widget will show the resendMessage indicator
|
||||||
|
final bool showResendMessage;
|
||||||
|
|
||||||
final List<Read> readList;
|
final List<Read> readList;
|
||||||
|
|
||||||
/// If true show the users username next to the timestamp of the message
|
/// If true show the users username next to the timestamp of the message
|
||||||
@@ -165,6 +168,7 @@ class MessageWidget extends StatefulWidget {
|
|||||||
this.editMessageInputBuilder,
|
this.editMessageInputBuilder,
|
||||||
this.textBuilder,
|
this.textBuilder,
|
||||||
Map<String, AttachmentBuilder> customAttachmentBuilders,
|
Map<String, AttachmentBuilder> customAttachmentBuilders,
|
||||||
|
this.showResendMessage = true,
|
||||||
this.readList,
|
this.readList,
|
||||||
this.padding,
|
this.padding,
|
||||||
this.textPadding = const EdgeInsets.symmetric(
|
this.textPadding = const EdgeInsets.symmetric(
|
||||||
@@ -232,13 +236,29 @@ class _MessageWidgetState extends State<MessageWidget> {
|
|||||||
bool get showTimeStamp =>
|
bool get showTimeStamp =>
|
||||||
widget.message.createdAt != null && widget.showTimestamp;
|
widget.message.createdAt != null && widget.showTimestamp;
|
||||||
|
|
||||||
bool get showReadList => widget.readList?.isNotEmpty == true;
|
bool get isMessageRead => widget.readList?.isNotEmpty == true;
|
||||||
|
|
||||||
bool get showInChannel =>
|
bool get showInChannel =>
|
||||||
widget.showInChannelIndicator && widget.message?.showInChannel == true;
|
widget.showInChannelIndicator && widget.message?.showInChannel == true;
|
||||||
|
|
||||||
bool get _hasReplyToMessage => widget.message?.replyToMessage != null;
|
bool get _hasReplyToMessage => widget.message?.replyToMessage != null;
|
||||||
|
|
||||||
|
bool get isSendFailed => widget.message.status == MessageSendingStatus.FAILED;
|
||||||
|
|
||||||
|
bool get isUpdateFailed =>
|
||||||
|
widget.message.status == MessageSendingStatus.FAILED_UPDATE;
|
||||||
|
|
||||||
|
bool get isDeleteFailed =>
|
||||||
|
widget.message.status == MessageSendingStatus.FAILED_DELETE;
|
||||||
|
|
||||||
|
bool get isFailedState => isSendFailed || isUpdateFailed || isDeleteFailed;
|
||||||
|
|
||||||
|
bool get showBottomRow =>
|
||||||
|
showThreadReplyIndicator ||
|
||||||
|
showUsername ||
|
||||||
|
showTimeStamp ||
|
||||||
|
showInChannel;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var leftPadding = widget.showUserAvatar != DisplayWidget.gone
|
var leftPadding = widget.showUserAvatar != DisplayWidget.gone
|
||||||
@@ -273,6 +293,7 @@ class _MessageWidgetState extends State<MessageWidget> {
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Stack(
|
Stack(
|
||||||
|
clipBehavior: Clip.none,
|
||||||
alignment: AlignmentDirectional.bottomStart,
|
alignment: AlignmentDirectional.bottomStart,
|
||||||
children: [
|
children: [
|
||||||
Column(
|
Column(
|
||||||
@@ -317,97 +338,90 @@ class _MessageWidgetState extends State<MessageWidget> {
|
|||||||
: 0,
|
: 0,
|
||||||
)
|
)
|
||||||
: EdgeInsets.zero,
|
: EdgeInsets.zero,
|
||||||
child:
|
child: (widget.message.isDeleted &&
|
||||||
(widget.message.isDeleted &&
|
!isFailedState)
|
||||||
widget.message.status !=
|
? Transform(
|
||||||
MessageSendingStatus
|
alignment: Alignment.center,
|
||||||
.FAILED_DELETE)
|
transform: Matrix4.rotationY(
|
||||||
? Transform(
|
widget.reverse ? pi : 0),
|
||||||
alignment: Alignment.center,
|
child: DeletedMessage(
|
||||||
transform: Matrix4.rotationY(
|
reverse: widget.reverse,
|
||||||
widget.reverse ? pi : 0),
|
borderRadiusGeometry:
|
||||||
child: DeletedMessage(
|
widget.borderRadiusGeometry,
|
||||||
reverse: widget.reverse,
|
borderSide: widget.borderSide,
|
||||||
borderRadiusGeometry: widget
|
shape: widget.shape,
|
||||||
.borderRadiusGeometry,
|
messageTheme:
|
||||||
borderSide:
|
widget.messageTheme,
|
||||||
widget.borderSide,
|
),
|
||||||
shape: widget.shape,
|
)
|
||||||
messageTheme:
|
: GestureDetector(
|
||||||
widget.messageTheme,
|
onLongPress: () =>
|
||||||
),
|
onLongPress(context),
|
||||||
)
|
child: Material(
|
||||||
: GestureDetector(
|
clipBehavior: Clip.antiAlias,
|
||||||
onTap: () =>
|
shape: widget.shape ??
|
||||||
retryMessage(context),
|
RoundedRectangleBorder(
|
||||||
onLongPress: () =>
|
side: isOnlyEmoji
|
||||||
onLongPress(context),
|
? BorderSide.none
|
||||||
child: Material(
|
: widget.borderSide ??
|
||||||
clipBehavior:
|
BorderSide(
|
||||||
Clip.antiAlias,
|
color: Theme.of(context)
|
||||||
shape: widget.shape ??
|
.brightness ==
|
||||||
RoundedRectangleBorder(
|
Brightness
|
||||||
side: isOnlyEmoji &&
|
.dark
|
||||||
!_hasReplyToMessage
|
|
||||||
? BorderSide.none
|
|
||||||
: widget.borderSide ??
|
|
||||||
BorderSide(
|
|
||||||
color: Theme.of(context).brightness ==
|
|
||||||
Brightness
|
|
||||||
.dark
|
|
||||||
? Colors
|
|
||||||
.white
|
|
||||||
.withAlpha(
|
|
||||||
24)
|
|
||||||
: Colors
|
|
||||||
.black
|
|
||||||
.withAlpha(24),
|
|
||||||
),
|
|
||||||
borderRadius: widget
|
|
||||||
.borderRadiusGeometry ??
|
|
||||||
BorderRadius.zero,
|
|
||||||
),
|
|
||||||
color:
|
|
||||||
_getBackgroundColor(),
|
|
||||||
child: Padding(
|
|
||||||
padding: EdgeInsets.all(
|
|
||||||
hasFiles ? 2.0 : 0.0),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment:
|
|
||||||
CrossAxisAlignment
|
|
||||||
.start,
|
|
||||||
mainAxisSize:
|
|
||||||
MainAxisSize.min,
|
|
||||||
children: <Widget>[
|
|
||||||
if (_hasReplyToMessage)
|
|
||||||
ReplyToMessageWidget(
|
|
||||||
message: widget
|
|
||||||
.message
|
|
||||||
.replyToMessage,
|
|
||||||
messageTheme: isMyMessage
|
|
||||||
? StreamChatTheme.of(
|
? StreamChatTheme.of(
|
||||||
context)
|
context)
|
||||||
.otherMessageTheme
|
.colorTheme
|
||||||
|
.white
|
||||||
|
.withAlpha(
|
||||||
|
24)
|
||||||
: StreamChatTheme.of(
|
: StreamChatTheme.of(
|
||||||
context)
|
context)
|
||||||
.ownMessageTheme,
|
.colorTheme
|
||||||
reverse: widget
|
.black
|
||||||
.reverse,
|
.withAlpha(
|
||||||
|
24),
|
||||||
),
|
),
|
||||||
..._parseAttachments(
|
borderRadius: widget
|
||||||
context),
|
.borderRadiusGeometry ??
|
||||||
if (widget
|
BorderRadius.zero,
|
||||||
.message.text
|
|
||||||
.trim()
|
|
||||||
.isNotEmpty &&
|
|
||||||
!isGiphy)
|
|
||||||
_buildTextBubble(
|
|
||||||
context),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
color: _getBackgroundColor(),
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(
|
||||||
|
hasFiles ? 2.0 : 0.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment:
|
||||||
|
CrossAxisAlignment.start,
|
||||||
|
mainAxisSize:
|
||||||
|
MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
if (_hasReplyToMessage)
|
||||||
|
ReplyToMessageWidget(
|
||||||
|
message: widget
|
||||||
|
.message
|
||||||
|
.replyToMessage,
|
||||||
|
messageTheme: isMyMessage
|
||||||
|
? StreamChatTheme.of(
|
||||||
|
context)
|
||||||
|
.otherMessageTheme
|
||||||
|
: StreamChatTheme.of(
|
||||||
|
context)
|
||||||
|
.ownMessageTheme,
|
||||||
|
reverse: widget
|
||||||
|
.reverse,
|
||||||
|
),
|
||||||
|
..._parseAttachments(
|
||||||
|
context),
|
||||||
|
if (widget.message.text
|
||||||
|
.trim()
|
||||||
|
.isNotEmpty &&
|
||||||
|
!isGiphy)
|
||||||
|
_buildTextBubble(context),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
),),
|
||||||
),
|
),
|
||||||
if (widget.showReactionPickerIndicator)
|
if (widget.showReactionPickerIndicator)
|
||||||
Positioned(
|
Positioned(
|
||||||
@@ -432,18 +446,23 @@ class _MessageWidgetState extends State<MessageWidget> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (showThreadReplyIndicator ||
|
if (showBottomRow) SizedBox(height: 20.0),
|
||||||
showUsername ||
|
|
||||||
showTimeStamp ||
|
|
||||||
showInChannel)
|
|
||||||
SizedBox(height: 20.0),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (showThreadReplyIndicator ||
|
if (showBottomRow) _buildBottomRow(leftPadding),
|
||||||
showUsername ||
|
if (isFailedState)
|
||||||
showTimeStamp ||
|
Positioned(
|
||||||
showInChannel)
|
left: widget.reverse ? -3 : null,
|
||||||
_buildBottomRow(leftPadding)
|
right: widget.reverse ? null : -9,
|
||||||
|
bottom: showBottomRow ? 20 : 0,
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
),
|
||||||
|
child: StreamSvgIcon.error(size: 20),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -463,16 +482,18 @@ class _MessageWidgetState extends State<MessageWidget> {
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
StreamSvgIcon.eye(
|
StreamSvgIcon.eye(
|
||||||
color: Colors.black.withOpacity(0.5),
|
color:
|
||||||
|
StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5),
|
||||||
size: 16.0,
|
size: 16.0,
|
||||||
),
|
),
|
||||||
SizedBox(width: 8.0),
|
SizedBox(width: 8.0),
|
||||||
Text(
|
Text(
|
||||||
'Only visible to you',
|
'Only visible to you',
|
||||||
style: TextStyle(
|
style: StreamChatTheme.of(context).textTheme.footnote.copyWith(
|
||||||
color: Colors.black.withOpacity(0.5),
|
color: StreamChatTheme.of(context)
|
||||||
fontSize: 12.0,
|
.colorTheme
|
||||||
),
|
.black
|
||||||
|
.withOpacity(0.5)),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -510,14 +531,14 @@ class _MessageWidgetState extends State<MessageWidget> {
|
|||||||
|
|
||||||
children.addAll([
|
children.addAll([
|
||||||
if (showSendingIndicator) _buildSendingIndicator(),
|
if (showSendingIndicator) _buildSendingIndicator(),
|
||||||
if (showReadList)
|
// if (showReadList)
|
||||||
SizedBox.fromSize(
|
// SizedBox.fromSize(
|
||||||
size: Size((widget.readList.length * 10.0) + 10, 17),
|
// size: Size((widget.readList.length * 10.0) + 10, 17),
|
||||||
child: Padding(
|
// child: Padding(
|
||||||
padding: const EdgeInsets.only(left: 4.0),
|
// padding: const EdgeInsets.only(left: 4.0),
|
||||||
child: _buildReadIndicator(),
|
// child: _buildReadIndicator(),
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
if (showThreadReplyIndicator)
|
if (showThreadReplyIndicator)
|
||||||
InkWell(
|
InkWell(
|
||||||
onTap: widget.onThreadTap != null ? onThreadTap : null,
|
onTap: widget.onThreadTap != null ? onThreadTap : null,
|
||||||
@@ -551,6 +572,7 @@ class _MessageWidgetState extends State<MessageWidget> {
|
|||||||
child: CustomPaint(
|
child: CustomPaint(
|
||||||
size: const Size(16, 32),
|
size: const Size(16, 32),
|
||||||
painter: _ThreadReplyPainter(
|
painter: _ThreadReplyPainter(
|
||||||
|
context: context,
|
||||||
color: widget.messageTheme.replyThreadColor,
|
color: widget.messageTheme.replyThreadColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -599,7 +621,7 @@ class _MessageWidgetState extends State<MessageWidget> {
|
|||||||
bottom: 0,
|
bottom: 0,
|
||||||
top: 0,
|
top: 0,
|
||||||
child: Material(
|
child: Material(
|
||||||
color: Colors.white,
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
clipBehavior: Clip.antiAlias,
|
clipBehavior: Clip.antiAlias,
|
||||||
shape: CircleBorder(),
|
shape: CircleBorder(),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
@@ -669,15 +691,20 @@ class _MessageWidgetState extends State<MessageWidget> {
|
|||||||
editMessageInputBuilder: widget.editMessageInputBuilder,
|
editMessageInputBuilder: widget.editMessageInputBuilder,
|
||||||
onReplyTap: widget.onReplyTap,
|
onReplyTap: widget.onReplyTap,
|
||||||
onThreadReplyTap: widget.onThreadTap,
|
onThreadReplyTap: widget.onThreadTap,
|
||||||
showCopyMessage: widget.message.text?.trim()?.isNotEmpty == true,
|
showResendMessage:
|
||||||
showEditMessage: widget.showEditMessage &&
|
widget.showResendMessage && (isSendFailed || isUpdateFailed),
|
||||||
|
showCopyMessage: !isFailedState &&
|
||||||
|
widget.message.text?.trim()?.isNotEmpty == true, showEditMessage: widget.showEditMessage &&
|
||||||
|
!isDeleteFailed &&
|
||||||
widget.message.attachments
|
widget.message.attachments
|
||||||
?.any((element) => element.type == 'giphy') !=
|
?.any((element) => element.type == 'giphy') !=
|
||||||
true,
|
true,
|
||||||
showReactions: widget.showReactions,
|
showReactions: widget.showReactions,
|
||||||
showReply: widget.showReplyIndicator,
|
showReply: widget.showReplyIndicator &&
|
||||||
|
!isFailedState &&
|
||||||
|
widget.onReplyTap != null,
|
||||||
showThreadReply:
|
showThreadReply:
|
||||||
widget.showThreadReplyIndicator && widget.onThreadTap != null,
|
widget.showThreadReplyIndicator && widget.onThreadTap != null,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -714,8 +741,8 @@ class _MessageWidgetState extends State<MessageWidget> {
|
|||||||
widget.borderSide ??
|
widget.borderSide ??
|
||||||
BorderSide(
|
BorderSide(
|
||||||
color: Theme.of(context).brightness == Brightness.dark
|
color: Theme.of(context).brightness == Brightness.dark
|
||||||
? Colors.white.withAlpha(24)
|
? StreamChatTheme.of(context).colorTheme.white.withAlpha(24)
|
||||||
: Colors.black.withAlpha(24),
|
: StreamChatTheme.of(context).colorTheme.black.withAlpha(24),
|
||||||
),
|
),
|
||||||
borderRadius: widget.attachmentBorderRadiusGeometry ??
|
borderRadius: widget.attachmentBorderRadiusGeometry ??
|
||||||
widget.borderRadiusGeometry ??
|
widget.borderRadiusGeometry ??
|
||||||
@@ -780,32 +807,22 @@ class _MessageWidgetState extends State<MessageWidget> {
|
|||||||
final attachmentShape =
|
final attachmentShape =
|
||||||
widget.attachmentShape ?? widget.shape ?? _getDefaultShape(context);
|
widget.attachmentShape ?? widget.shape ?? _getDefaultShape(context);
|
||||||
return Material(
|
return Material(
|
||||||
color: _getBackgroundColor(),
|
color: _getBackgroundColor(),
|
||||||
clipBehavior: Clip.antiAlias,
|
clipBehavior: Clip.antiAlias,
|
||||||
shape: attachmentShape,
|
shape: attachmentShape,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: widget.attachmentPadding,
|
padding: widget.attachmentPadding,
|
||||||
child: Material(
|
child: Material(
|
||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.hardEdge,
|
||||||
shape: attachmentShape,
|
shape: attachmentShape,
|
||||||
type: MaterialType.transparency,
|
type: MaterialType.transparency,
|
||||||
child: Transform(
|
child: Transform(
|
||||||
transform: Matrix4.rotationY(widget.reverse ? pi : 0),
|
transform: Matrix4.rotationY(widget.reverse ? pi : 0),
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
child: Column(
|
child: attachmentWidget,
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
|
||||||
children: <Widget>[
|
|
||||||
getFailedMessageWidget(
|
|
||||||
context,
|
|
||||||
padding: const EdgeInsets.all(8.0),
|
|
||||||
),
|
|
||||||
attachmentWidget,
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -824,14 +841,27 @@ class _MessageWidgetState extends State<MessageWidget> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildSendingIndicator() {
|
Widget _buildSendingIndicator() {
|
||||||
return Container(
|
final style = widget.messageTheme.createdAt;
|
||||||
height: widget.messageTheme.createdAt.fontSize + 2,
|
Widget child = SendingIndicator(
|
||||||
width: widget.messageTheme.createdAt.fontSize + 2,
|
message: widget.message,
|
||||||
child: SendingIndicator(
|
isMessageRead: isMessageRead,
|
||||||
message: widget.message,
|
size: style.fontSize,
|
||||||
allRead: widget.allRead,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
if (isMessageRead) {
|
||||||
|
child = Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
widget.readList.length.toString(),
|
||||||
|
style: style.copyWith(
|
||||||
|
color: StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(width: 2),
|
||||||
|
child,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return child;
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildUserAvatar() => Transform(
|
Widget _buildUserAvatar() => Transform(
|
||||||
@@ -856,55 +886,6 @@ class _MessageWidgetState extends State<MessageWidget> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget getFailedMessageWidget(
|
|
||||||
BuildContext context, {
|
|
||||||
EdgeInsetsGeometry padding,
|
|
||||||
}) {
|
|
||||||
Widget failedWidget;
|
|
||||||
if (widget.message.status == MessageSendingStatus.FAILED) {
|
|
||||||
failedWidget = Text(
|
|
||||||
'MESSAGE FAILED · CLICK TO TRY AGAIN',
|
|
||||||
style: widget.messageTheme.messageText.copyWith(
|
|
||||||
color: Theme.of(context).brightness == Brightness.dark
|
|
||||||
? Colors.white.withOpacity(.5)
|
|
||||||
: Colors.black.withOpacity(.5),
|
|
||||||
fontSize: 11,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (widget.message.status == MessageSendingStatus.FAILED_UPDATE) {
|
|
||||||
failedWidget = Text(
|
|
||||||
'MESSAGE UPDATE FAILED · CLICK TO TRY AGAIN',
|
|
||||||
style: widget.messageTheme.messageText.copyWith(
|
|
||||||
color: Theme.of(context).brightness == Brightness.dark
|
|
||||||
? Colors.white.withOpacity(.5)
|
|
||||||
: Colors.black.withOpacity(.5),
|
|
||||||
fontSize: 11,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (widget.message.status == MessageSendingStatus.FAILED_DELETE) {
|
|
||||||
failedWidget = Text(
|
|
||||||
'MESSAGE DELETE FAILED · CLICK TO TRY AGAIN',
|
|
||||||
style: widget.messageTheme.messageText.copyWith(
|
|
||||||
color: Theme.of(context).brightness == Brightness.dark
|
|
||||||
? Colors.white.withOpacity(.5)
|
|
||||||
: Colors.black.withOpacity(.5),
|
|
||||||
fontSize: 11,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (failedWidget != null) {
|
|
||||||
return Padding(
|
|
||||||
padding: padding ?? EdgeInsets.zero,
|
|
||||||
child: failedWidget,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return SizedBox();
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildTextBubble(BuildContext context) {
|
Widget _buildTextBubble(BuildContext context) {
|
||||||
return Transform(
|
return Transform(
|
||||||
transform: Matrix4.rotationY(widget.reverse ? pi : 0),
|
transform: Matrix4.rotationY(widget.reverse ? pi : 0),
|
||||||
@@ -914,26 +895,20 @@ class _MessageWidgetState extends State<MessageWidget> {
|
|||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: widget.textPadding,
|
padding: widget.textPadding,
|
||||||
child: Column(
|
child: widget.textBuilder != null
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
? widget.textBuilder(context, widget.message)
|
||||||
children: [
|
: MessageText(
|
||||||
getFailedMessageWidget(context),
|
onLinkTap: widget.onLinkTap,
|
||||||
widget.textBuilder != null
|
message: widget.message,
|
||||||
? widget.textBuilder(context, widget.message)
|
onMentionTap: widget.onMentionTap,
|
||||||
: MessageText(
|
messageTheme: isOnlyEmoji
|
||||||
onLinkTap: widget.onLinkTap,
|
? widget.messageTheme.copyWith(
|
||||||
message: widget.message,
|
messageText:
|
||||||
onMentionTap: widget.onMentionTap,
|
widget.messageTheme.messageText.copyWith(
|
||||||
messageTheme: isOnlyEmoji
|
fontSize: 40,
|
||||||
? widget.messageTheme.copyWith(
|
))
|
||||||
messageText:
|
: widget.messageTheme,
|
||||||
widget.messageTheme.messageText.copyWith(
|
),
|
||||||
fontSize: 40,
|
|
||||||
))
|
|
||||||
: widget.messageTheme,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
if (widget.message.attachments
|
if (widget.message.attachments
|
||||||
?.any((element) => element.ogScrapeUrl != null) ==
|
?.any((element) => element.ogScrapeUrl != null) ==
|
||||||
@@ -954,16 +929,10 @@ class _MessageWidgetState extends State<MessageWidget> {
|
|||||||
return widget.messageTheme.messageBackgroundColor;
|
return widget.messageTheme.messageBackgroundColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((widget.message.status == MessageSendingStatus.FAILED ||
|
|
||||||
widget.message.status == MessageSendingStatus.FAILED_UPDATE ||
|
|
||||||
widget.message.status == MessageSendingStatus.FAILED_DELETE)) {
|
|
||||||
return Color(0xffd0021B).withOpacity(.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (widget.message.attachments
|
if (widget.message.attachments
|
||||||
?.any((element) => element.ogScrapeUrl != null) ==
|
?.any((element) => element.ogScrapeUrl != null) ==
|
||||||
true) {
|
true) {
|
||||||
return Color(0xFFE9F2FF);
|
return StreamChatTheme.of(context).colorTheme.blueAlice;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isOnlyEmoji) {
|
if (isOnlyEmoji) {
|
||||||
@@ -1003,13 +972,14 @@ class _MessageWidgetState extends State<MessageWidget> {
|
|||||||
|
|
||||||
class _ThreadReplyPainter extends CustomPainter {
|
class _ThreadReplyPainter extends CustomPainter {
|
||||||
final Color color;
|
final Color color;
|
||||||
|
final BuildContext context;
|
||||||
|
|
||||||
const _ThreadReplyPainter({@required this.color});
|
const _ThreadReplyPainter({this.context, @required this.color});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void paint(Canvas canvas, Size size) {
|
void paint(Canvas canvas, Size size) {
|
||||||
final paint = Paint()
|
final paint = Paint()
|
||||||
..color = color ?? Color(0XFFDBDBDB)
|
..color = color ?? StreamChatTheme.of(context).colorTheme.greyGainsboro
|
||||||
..style = PaintingStyle.stroke
|
..style = PaintingStyle.stroke
|
||||||
..strokeWidth = 1
|
..strokeWidth = 1
|
||||||
..strokeCap = StrokeCap.round;
|
..strokeCap = StrokeCap.round;
|
||||||
|
|||||||
@@ -107,16 +107,22 @@ class ReactionBubble extends StatelessWidget {
|
|||||||
height: 16,
|
height: 16,
|
||||||
color: (!highlightOwnReactions ||
|
color: (!highlightOwnReactions ||
|
||||||
reaction.user.id == StreamChat.of(context).user.id)
|
reaction.user.id == StreamChat.of(context).user.id)
|
||||||
? StreamChatTheme.of(context).accentColor
|
? StreamChatTheme.of(context).colorTheme.accentBlue
|
||||||
: Colors.black.withOpacity(.5),
|
: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(.5),
|
||||||
)
|
)
|
||||||
: Icon(
|
: Icon(
|
||||||
Icons.help_outline_rounded,
|
Icons.help_outline_rounded,
|
||||||
size: 16,
|
size: 16,
|
||||||
color: (!highlightOwnReactions ||
|
color: (!highlightOwnReactions ||
|
||||||
reaction.user.id == StreamChat.of(context).user.id)
|
reaction.user.id == StreamChat.of(context).user.id)
|
||||||
? StreamChatTheme.of(context).accentColor
|
? StreamChatTheme.of(context).colorTheme.accentBlue
|
||||||
: Colors.black.withOpacity(.5),
|
: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(.5),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,7 +89,9 @@ class _ReactionPickerState extends State<ReactionPicker>
|
|||||||
height: animations[index].value * 24.0,
|
height: animations[index].value * 24.0,
|
||||||
width: animations[index].value * 24.0,
|
width: animations[index].value * 24.0,
|
||||||
color: ownReactionIndex != -1
|
color: ownReactionIndex != -1
|
||||||
? StreamChatTheme.of(context).accentColor
|
? StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.accentBlue
|
||||||
: Theme.of(context)
|
: Theme.of(context)
|
||||||
.iconTheme
|
.iconTheme
|
||||||
.color
|
.color
|
||||||
|
|||||||
@@ -4,27 +4,29 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
|||||||
/// Used to show the sending status of the message
|
/// Used to show the sending status of the message
|
||||||
class SendingIndicator extends StatelessWidget {
|
class SendingIndicator extends StatelessWidget {
|
||||||
final Message message;
|
final Message message;
|
||||||
final bool allRead;
|
final bool isMessageRead;
|
||||||
|
final double size;
|
||||||
|
|
||||||
const SendingIndicator({
|
const SendingIndicator({
|
||||||
Key key,
|
Key key,
|
||||||
this.message,
|
this.message,
|
||||||
this.allRead = false,
|
this.isMessageRead = false,
|
||||||
|
this.size = 12,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (allRead) {
|
if (isMessageRead) {
|
||||||
return Icon(
|
return Icon(
|
||||||
Icons.done_all,
|
Icons.done_all_rounded,
|
||||||
size: 8,
|
size: size,
|
||||||
color: StreamChatTheme.of(context).accentColor,
|
color: StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (message.status == MessageSendingStatus.SENT || message.status == null) {
|
if (message.status == MessageSendingStatus.SENT || message.status == null) {
|
||||||
return Icon(
|
return Icon(
|
||||||
Icons.done,
|
Icons.done,
|
||||||
size: 8,
|
size: size,
|
||||||
color: IconTheme.of(context).color.withOpacity(0.5),
|
color: IconTheme.of(context).color.withOpacity(0.5),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -32,18 +34,9 @@ class SendingIndicator extends StatelessWidget {
|
|||||||
message.status == MessageSendingStatus.UPDATING) {
|
message.status == MessageSendingStatus.UPDATING) {
|
||||||
return Icon(
|
return Icon(
|
||||||
Icons.access_time,
|
Icons.access_time,
|
||||||
size: 8,
|
size: size,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (message.status == MessageSendingStatus.FAILED ||
|
|
||||||
message.status == MessageSendingStatus.FAILED_UPDATE ||
|
|
||||||
message.status == MessageSendingStatus.FAILED_DELETE) {
|
|
||||||
return Icon(
|
|
||||||
Icons.error_outline,
|
|
||||||
size: 8,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return SizedBox();
|
return SizedBox();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,8 +76,8 @@ class StreamChatState extends State<StreamChat> with WidgetsBindingObserver {
|
|||||||
return Theme(
|
return Theme(
|
||||||
data: materialTheme.copyWith(
|
data: materialTheme.copyWith(
|
||||||
primaryIconTheme: streamTheme.primaryIconTheme,
|
primaryIconTheme: streamTheme.primaryIconTheme,
|
||||||
accentColor: streamTheme.accentColor,
|
accentColor: streamTheme.colorTheme.accentBlue,
|
||||||
scaffoldBackgroundColor: streamTheme.backgroundColor,
|
scaffoldBackgroundColor: streamTheme.colorTheme.white,
|
||||||
),
|
),
|
||||||
child: widget.child,
|
child: widget.child,
|
||||||
);
|
);
|
||||||
@@ -92,11 +92,9 @@ class StreamChatState extends State<StreamChat> with WidgetsBindingObserver {
|
|||||||
) {
|
) {
|
||||||
final defaultTheme = StreamChatThemeData.getDefaultTheme(Theme.of(context));
|
final defaultTheme = StreamChatThemeData.getDefaultTheme(Theme.of(context));
|
||||||
final theme = defaultTheme.copyWith(
|
final theme = defaultTheme.copyWith(
|
||||||
primaryColor: themeData?.primaryColor,
|
|
||||||
defaultChannelImage: themeData?.defaultChannelImage,
|
defaultChannelImage: themeData?.defaultChannelImage,
|
||||||
primaryIconTheme: themeData?.primaryIconTheme,
|
primaryIconTheme: themeData?.primaryIconTheme,
|
||||||
defaultUserImage: themeData?.defaultUserImage,
|
defaultUserImage: themeData?.defaultUserImage,
|
||||||
backgroundColor: themeData?.backgroundColor,
|
|
||||||
channelTheme: defaultTheme.channelTheme.copyWith(
|
channelTheme: defaultTheme.channelTheme.copyWith(
|
||||||
channelHeaderTheme:
|
channelHeaderTheme:
|
||||||
defaultTheme.channelTheme.channelHeaderTheme.copyWith(
|
defaultTheme.channelTheme.channelHeaderTheme.copyWith(
|
||||||
@@ -151,8 +149,6 @@ class StreamChatState extends State<StreamChat> with WidgetsBindingObserver {
|
|||||||
reactionsBackgroundColor:
|
reactionsBackgroundColor:
|
||||||
themeData?.otherMessageTheme?.reactionsBackgroundColor,
|
themeData?.otherMessageTheme?.reactionsBackgroundColor,
|
||||||
),
|
),
|
||||||
accentColor: themeData?.accentColor,
|
|
||||||
secondaryColor: themeData?.secondaryColor,
|
|
||||||
channelPreviewTheme: defaultTheme.channelPreviewTheme.copyWith(
|
channelPreviewTheme: defaultTheme.channelPreviewTheme.copyWith(
|
||||||
avatarTheme: defaultTheme.channelPreviewTheme.avatarTheme.copyWith(
|
avatarTheme: defaultTheme.channelPreviewTheme.avatarTheme.copyWith(
|
||||||
constraints: themeData?.channelPreviewTheme?.avatarTheme?.constraints,
|
constraints: themeData?.channelPreviewTheme?.avatarTheme?.constraints,
|
||||||
|
|||||||
+285
-81
@@ -42,17 +42,11 @@ class StreamChatTheme extends InheritedWidget {
|
|||||||
|
|
||||||
/// Theme data
|
/// Theme data
|
||||||
class StreamChatThemeData {
|
class StreamChatThemeData {
|
||||||
/// Primary color of the chat widgets
|
/// The text themes used in the widgets
|
||||||
final Color primaryColor;
|
final TextTheme textTheme;
|
||||||
|
|
||||||
/// Secondary color of the chat widgets
|
/// The text themes used in the widgets
|
||||||
final Color secondaryColor;
|
final ColorTheme colorTheme;
|
||||||
|
|
||||||
/// Accent color of the chat widgets
|
|
||||||
final Color accentColor;
|
|
||||||
|
|
||||||
/// Background color of the chat widgets
|
|
||||||
final Color backgroundColor;
|
|
||||||
|
|
||||||
/// Theme of the [ChannelPreview]
|
/// Theme of the [ChannelPreview]
|
||||||
final ChannelPreviewTheme channelPreviewTheme;
|
final ChannelPreviewTheme channelPreviewTheme;
|
||||||
@@ -80,10 +74,8 @@ class StreamChatThemeData {
|
|||||||
|
|
||||||
/// Create a theme from scratch
|
/// Create a theme from scratch
|
||||||
StreamChatThemeData({
|
StreamChatThemeData({
|
||||||
this.primaryColor,
|
this.textTheme,
|
||||||
this.secondaryColor,
|
this.colorTheme,
|
||||||
this.accentColor,
|
|
||||||
this.backgroundColor,
|
|
||||||
this.channelPreviewTheme,
|
this.channelPreviewTheme,
|
||||||
this.channelTheme,
|
this.channelTheme,
|
||||||
this.otherMessageTheme,
|
this.otherMessageTheme,
|
||||||
@@ -99,11 +91,7 @@ class StreamChatThemeData {
|
|||||||
final defaultTheme = getDefaultTheme(theme);
|
final defaultTheme = getDefaultTheme(theme);
|
||||||
|
|
||||||
return defaultTheme.copyWith(
|
return defaultTheme.copyWith(
|
||||||
accentColor: theme.accentColor,
|
|
||||||
primaryIconTheme: theme.primaryIconTheme,
|
primaryIconTheme: theme.primaryIconTheme,
|
||||||
primaryColor: theme.colorScheme.primary,
|
|
||||||
secondaryColor: theme.colorScheme.secondary,
|
|
||||||
backgroundColor: theme.scaffoldBackgroundColor,
|
|
||||||
channelTheme: defaultTheme.channelTheme.copyWith(
|
channelTheme: defaultTheme.channelTheme.copyWith(
|
||||||
inputGradient: LinearGradient(colors: [
|
inputGradient: LinearGradient(colors: [
|
||||||
theme.accentColor.withOpacity(.5),
|
theme.accentColor.withOpacity(.5),
|
||||||
@@ -131,10 +119,8 @@ class StreamChatThemeData {
|
|||||||
|
|
||||||
/// Creates a copy of [StreamChatThemeData] with specified attributes overridden.
|
/// Creates a copy of [StreamChatThemeData] with specified attributes overridden.
|
||||||
StreamChatThemeData copyWith({
|
StreamChatThemeData copyWith({
|
||||||
Color primaryColor,
|
TextTheme textTheme,
|
||||||
Color secondaryColor,
|
ColorTheme colorTheme,
|
||||||
Color accentColor,
|
|
||||||
Color backgroundColor,
|
|
||||||
ChannelPreviewTheme channelPreviewTheme,
|
ChannelPreviewTheme channelPreviewTheme,
|
||||||
ChannelTheme channelTheme,
|
ChannelTheme channelTheme,
|
||||||
MessageTheme ownMessageTheme,
|
MessageTheme ownMessageTheme,
|
||||||
@@ -145,24 +131,35 @@ class StreamChatThemeData {
|
|||||||
List<ReactionIcon> reactionIcons,
|
List<ReactionIcon> reactionIcons,
|
||||||
}) =>
|
}) =>
|
||||||
StreamChatThemeData(
|
StreamChatThemeData(
|
||||||
primaryColor: primaryColor ?? this.primaryColor,
|
textTheme: this.textTheme?.copyWith(
|
||||||
secondaryColor: secondaryColor ?? this.secondaryColor,
|
title: textTheme?.title,
|
||||||
|
body: textTheme?.body,
|
||||||
|
bodyBold: textTheme?.bodyBold,
|
||||||
|
captionBold: textTheme?.captionBold,
|
||||||
|
footnote: textTheme?.footnote,
|
||||||
|
footnoteBold: textTheme?.footnoteBold,
|
||||||
|
headline: textTheme?.headline,
|
||||||
|
headlineBold: textTheme?.headlineBold,
|
||||||
|
),
|
||||||
|
colorTheme: this.colorTheme?.copyWith(
|
||||||
|
black: colorTheme?.black,
|
||||||
|
grey: colorTheme?.grey,
|
||||||
|
greyGainsboro: colorTheme?.greyGainsboro,
|
||||||
|
greyWhisper: colorTheme?.greyWhisper,
|
||||||
|
whiteSmoke: colorTheme?.whiteSmoke,
|
||||||
|
whiteSnow: colorTheme?.whiteSnow,
|
||||||
|
white: colorTheme?.white,
|
||||||
|
blueAlice: colorTheme?.blueAlice,
|
||||||
|
),
|
||||||
primaryIconTheme: primaryIconTheme ?? this.primaryIconTheme,
|
primaryIconTheme: primaryIconTheme ?? this.primaryIconTheme,
|
||||||
accentColor: accentColor ?? this.accentColor,
|
|
||||||
defaultChannelImage: defaultChannelImage ?? this.defaultChannelImage,
|
defaultChannelImage: defaultChannelImage ?? this.defaultChannelImage,
|
||||||
defaultUserImage: defaultUserImage ?? this.defaultUserImage,
|
defaultUserImage: defaultUserImage ?? this.defaultUserImage,
|
||||||
backgroundColor: backgroundColor ?? this.backgroundColor,
|
channelPreviewTheme: this.channelPreviewTheme?.copyWith(
|
||||||
channelPreviewTheme: channelPreviewTheme?.copyWith(
|
title: channelPreviewTheme.title,
|
||||||
title:
|
subtitle: channelPreviewTheme.subtitle,
|
||||||
channelPreviewTheme.title ?? this.channelPreviewTheme.title,
|
lastMessageAt: channelPreviewTheme.lastMessageAt,
|
||||||
subtitle: channelPreviewTheme.subtitle ??
|
avatarTheme: channelPreviewTheme.avatarTheme,
|
||||||
this.channelPreviewTheme.subtitle,
|
),
|
||||||
lastMessageAt: channelPreviewTheme.lastMessageAt ??
|
|
||||||
this.channelPreviewTheme.lastMessageAt,
|
|
||||||
avatarTheme: channelPreviewTheme.avatarTheme ??
|
|
||||||
this.channelPreviewTheme.avatarTheme,
|
|
||||||
) ??
|
|
||||||
this.channelPreviewTheme,
|
|
||||||
channelTheme: channelTheme?.copyWith(
|
channelTheme: channelTheme?.copyWith(
|
||||||
channelHeaderTheme: channelTheme.channelHeaderTheme ??
|
channelHeaderTheme: channelTheme.channelHeaderTheme ??
|
||||||
this.channelTheme.channelHeaderTheme,
|
this.channelTheme.channelHeaderTheme,
|
||||||
@@ -222,14 +219,13 @@ class StreamChatThemeData {
|
|||||||
static StreamChatThemeData getDefaultTheme(ThemeData theme) {
|
static StreamChatThemeData getDefaultTheme(ThemeData theme) {
|
||||||
final accentColor = Color(0xff006cff);
|
final accentColor = Color(0xff006cff);
|
||||||
final isDark = theme.brightness == Brightness.dark;
|
final isDark = theme.brightness == Brightness.dark;
|
||||||
|
final textTheme = isDark ? TextTheme.dark() : TextTheme.light();
|
||||||
|
final colorTheme = isDark ? ColorTheme.dark() : ColorTheme.light();
|
||||||
return StreamChatThemeData(
|
return StreamChatThemeData(
|
||||||
secondaryColor: Color(0xffEAEAEA),
|
textTheme: textTheme,
|
||||||
accentColor: accentColor,
|
colorTheme: colorTheme,
|
||||||
primaryColor: isDark ? Colors.black : Colors.white,
|
primaryIconTheme: IconThemeData(color: colorTheme.black.withOpacity(.5)),
|
||||||
primaryIconTheme: IconThemeData(
|
|
||||||
color: isDark ? Colors.white : Colors.black.withOpacity(.5)),
|
|
||||||
defaultChannelImage: (context, channel) => SizedBox(),
|
defaultChannelImage: (context, channel) => SizedBox(),
|
||||||
backgroundColor: isDark ? Colors.black : Colors.white,
|
|
||||||
defaultUserImage: (context, user) => Center(
|
defaultUserImage: (context, user) => Center(
|
||||||
child: CachedNetworkImage(
|
child: CachedNetworkImage(
|
||||||
filterQuality: FilterQuality.high,
|
filterQuality: FilterQuality.high,
|
||||||
@@ -238,7 +234,7 @@ class StreamChatThemeData {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
channelPreviewTheme: ChannelPreviewTheme(
|
channelPreviewTheme: ChannelPreviewTheme(
|
||||||
unreadCounterColor: Color(0xffff3742),
|
unreadCounterColor: colorTheme.accentRed,
|
||||||
avatarTheme: AvatarTheme(
|
avatarTheme: AvatarTheme(
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
constraints: BoxConstraints.tightFor(
|
constraints: BoxConstraints.tightFor(
|
||||||
@@ -246,19 +242,12 @@ class StreamChatThemeData {
|
|||||||
width: 40,
|
width: 40,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
title: TextStyle(
|
title: textTheme.bodyBold,
|
||||||
fontSize: 14,
|
subtitle: textTheme.footnote.copyWith(
|
||||||
color: isDark ? Colors.white : Colors.black,
|
color: Color(0xff7A7A7A),
|
||||||
fontWeight: FontWeight.bold),
|
|
||||||
subtitle: TextStyle(
|
|
||||||
fontSize: 12.5,
|
|
||||||
color: (isDark ? Colors.white : Colors.black).withOpacity(0.5),
|
|
||||||
),
|
),
|
||||||
lastMessageAt: TextStyle(
|
lastMessageAt: textTheme.footnote.copyWith(
|
||||||
fontSize: 11,
|
color: colorTheme.black.withOpacity(.5),
|
||||||
color: isDark
|
|
||||||
? Colors.white.withOpacity(.5)
|
|
||||||
: Colors.black.withOpacity(.5),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
channelTheme: ChannelTheme(
|
channelTheme: ChannelTheme(
|
||||||
@@ -273,20 +262,17 @@ class StreamChatThemeData {
|
|||||||
width: 40,
|
width: 40,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
color: isDark ? Colors.black : Colors.white,
|
color: colorTheme.white,
|
||||||
title: TextStyle(
|
title: TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: isDark ? Colors.white : Colors.black,
|
color: colorTheme.black,
|
||||||
),
|
),
|
||||||
lastMessageAt: TextStyle(
|
lastMessageAt: TextStyle(
|
||||||
fontSize: 11,
|
fontSize: 11,
|
||||||
color: isDark
|
color: colorTheme.black.withOpacity(.5),
|
||||||
? Colors.white.withOpacity(.5)
|
|
||||||
: Colors.black.withOpacity(.5),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
inputBackground:
|
inputBackground: colorTheme.white.withAlpha(12),
|
||||||
isDark ? Colors.black.withAlpha(12) : Colors.white.withAlpha(12),
|
|
||||||
inputGradient: LinearGradient(colors: [
|
inputGradient: LinearGradient(colors: [
|
||||||
Color(0xFF00AEFF),
|
Color(0xFF00AEFF),
|
||||||
Color(0xFF0076FF),
|
Color(0xFF0076FF),
|
||||||
@@ -295,12 +281,10 @@ class StreamChatThemeData {
|
|||||||
ownMessageTheme: MessageTheme(
|
ownMessageTheme: MessageTheme(
|
||||||
messageText: TextStyle(
|
messageText: TextStyle(
|
||||||
fontSize: 14.5,
|
fontSize: 14.5,
|
||||||
color: isDark ? Colors.white : Colors.black,
|
color: colorTheme.black,
|
||||||
),
|
),
|
||||||
createdAt: TextStyle(
|
createdAt: TextStyle(
|
||||||
color: isDark
|
color: colorTheme.black.withOpacity(.5),
|
||||||
? Colors.white.withOpacity(.5)
|
|
||||||
: Colors.black.withOpacity(.5),
|
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
),
|
),
|
||||||
replies: TextStyle(
|
replies: TextStyle(
|
||||||
@@ -308,10 +292,10 @@ class StreamChatThemeData {
|
|||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
),
|
),
|
||||||
messageBackgroundColor: isDark ? Color(0xff191919) : Color(0xffEAEAEA),
|
messageBackgroundColor: colorTheme.greyGainsboro,
|
||||||
reactionsBackgroundColor: isDark ? Colors.black : Colors.white,
|
reactionsBackgroundColor: colorTheme.white,
|
||||||
reactionsBorderColor: isDark ? Color(0xff191919) : Color(0xffEAEAEA),
|
reactionsBorderColor: colorTheme.greyWhisper,
|
||||||
replyThreadColor: isDark ? Color(0xff191919) : Color(0xffEAEAEA),
|
replyThreadColor: colorTheme.greyWhisper,
|
||||||
avatarTheme: AvatarTheme(
|
avatarTheme: AvatarTheme(
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
constraints: BoxConstraints.tightFor(
|
constraints: BoxConstraints.tightFor(
|
||||||
@@ -324,17 +308,14 @@ class StreamChatThemeData {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
otherMessageTheme: MessageTheme(
|
otherMessageTheme: MessageTheme(
|
||||||
reactionsBackgroundColor:
|
reactionsBackgroundColor: colorTheme.greyGainsboro,
|
||||||
isDark ? Color(0xff191919) : Color(0xffEAEAEA),
|
reactionsBorderColor: colorTheme.white,
|
||||||
reactionsBorderColor: isDark ? Colors.black : Colors.white,
|
|
||||||
messageText: TextStyle(
|
messageText: TextStyle(
|
||||||
fontSize: 14.5,
|
fontSize: 14.5,
|
||||||
color: isDark ? Colors.white : Colors.black,
|
color: colorTheme.black,
|
||||||
),
|
),
|
||||||
createdAt: TextStyle(
|
createdAt: TextStyle(
|
||||||
color: isDark
|
color: colorTheme.black.withOpacity(.5),
|
||||||
? Colors.white.withOpacity(.5)
|
|
||||||
: Colors.black.withOpacity(.5),
|
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
),
|
),
|
||||||
replies: TextStyle(
|
replies: TextStyle(
|
||||||
@@ -345,9 +326,8 @@ class StreamChatThemeData {
|
|||||||
messageLinks: TextStyle(
|
messageLinks: TextStyle(
|
||||||
color: accentColor,
|
color: accentColor,
|
||||||
),
|
),
|
||||||
messageBackgroundColor: isDark ? Colors.black : Colors.white,
|
messageBackgroundColor: colorTheme.white,
|
||||||
replyThreadColor:
|
replyThreadColor: colorTheme.black.withAlpha(24),
|
||||||
isDark ? Colors.white.withAlpha(24) : Colors.black.withAlpha(24),
|
|
||||||
avatarTheme: AvatarTheme(
|
avatarTheme: AvatarTheme(
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
constraints: BoxConstraints.tightFor(
|
constraints: BoxConstraints.tightFor(
|
||||||
@@ -382,6 +362,230 @@ class StreamChatThemeData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum TextThemeType {
|
||||||
|
light,
|
||||||
|
dark,
|
||||||
|
}
|
||||||
|
|
||||||
|
class TextTheme {
|
||||||
|
final TextStyle title;
|
||||||
|
final TextStyle headlineBold;
|
||||||
|
final TextStyle headline;
|
||||||
|
final TextStyle bodyBold;
|
||||||
|
final TextStyle body;
|
||||||
|
final TextStyle footnoteBold;
|
||||||
|
final TextStyle footnote;
|
||||||
|
final TextStyle captionBold;
|
||||||
|
|
||||||
|
TextTheme.light({
|
||||||
|
this.title = const TextStyle(
|
||||||
|
fontSize: 22,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
this.headlineBold = const TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
this.headline = const TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
this.bodyBold = const TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
this.body = const TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
this.footnoteBold = const TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
this.footnote = const TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
this.captionBold = const TextStyle(
|
||||||
|
fontSize: 10,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
TextTheme.dark({
|
||||||
|
this.title = const TextStyle(
|
||||||
|
fontSize: 22,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
this.headlineBold = const TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
this.headline = const TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
this.bodyBold = const TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
this.body = const TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
this.footnoteBold = const TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
this.footnote = const TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
this.captionBold = const TextStyle(
|
||||||
|
fontSize: 10,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
TextTheme copyWith({
|
||||||
|
TextThemeType type = TextThemeType.light,
|
||||||
|
TextStyle body,
|
||||||
|
TextStyle title,
|
||||||
|
TextStyle headlineBold,
|
||||||
|
TextStyle headline,
|
||||||
|
TextStyle bodyBold,
|
||||||
|
TextStyle footnoteBold,
|
||||||
|
TextStyle footnote,
|
||||||
|
TextStyle captionBold,
|
||||||
|
}) {
|
||||||
|
return type == TextThemeType.light
|
||||||
|
? TextTheme.light(
|
||||||
|
body: body ?? this.body,
|
||||||
|
title: title ?? this.title,
|
||||||
|
headlineBold: headlineBold ?? this.headlineBold,
|
||||||
|
headline: headline ?? this.headline,
|
||||||
|
bodyBold: bodyBold ?? this.bodyBold,
|
||||||
|
footnoteBold: footnoteBold ?? this.footnoteBold,
|
||||||
|
footnote: footnote ?? this.footnote,
|
||||||
|
captionBold: captionBold ?? this.captionBold,
|
||||||
|
)
|
||||||
|
: TextTheme.dark(
|
||||||
|
body: body ?? this.body,
|
||||||
|
title: title ?? this.title,
|
||||||
|
headlineBold: headlineBold ?? this.headlineBold,
|
||||||
|
headline: headline ?? this.headline,
|
||||||
|
bodyBold: bodyBold ?? this.bodyBold,
|
||||||
|
footnoteBold: footnoteBold ?? this.footnoteBold,
|
||||||
|
footnote: footnote ?? this.footnote,
|
||||||
|
captionBold: captionBold ?? this.captionBold,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ColorThemeType {
|
||||||
|
light,
|
||||||
|
dark,
|
||||||
|
}
|
||||||
|
|
||||||
|
class ColorTheme {
|
||||||
|
final Color black;
|
||||||
|
final Color grey;
|
||||||
|
final Color greyGainsboro;
|
||||||
|
final Color greyWhisper;
|
||||||
|
final Color whiteSmoke;
|
||||||
|
final Color whiteSnow;
|
||||||
|
final Color white;
|
||||||
|
final Color blueAlice;
|
||||||
|
final Color accentBlue;
|
||||||
|
final Color accentRed;
|
||||||
|
final Color accentGreen;
|
||||||
|
|
||||||
|
ColorTheme.light({
|
||||||
|
this.black = const Color(0xff000000),
|
||||||
|
this.grey = const Color(0xff7a7a7a),
|
||||||
|
this.greyGainsboro = const Color(0xffdbdbdb),
|
||||||
|
this.greyWhisper = const Color(0xffecebeb),
|
||||||
|
this.whiteSmoke = const Color(0xfff2f2f2),
|
||||||
|
this.whiteSnow = const Color(0xfffcfcfc),
|
||||||
|
this.white = const Color(0xffffffff),
|
||||||
|
this.blueAlice = const Color(0xffe9f2ff),
|
||||||
|
this.accentBlue = const Color(0xff005FFF),
|
||||||
|
this.accentRed = const Color(0xffFF3742),
|
||||||
|
this.accentGreen = const Color(0xff20E070),
|
||||||
|
});
|
||||||
|
|
||||||
|
ColorTheme.dark({
|
||||||
|
this.black = const Color(0xffffffff),
|
||||||
|
this.grey = const Color(0xff7a7a7a),
|
||||||
|
this.greyGainsboro = const Color(0xff2d2f2f),
|
||||||
|
this.greyWhisper = const Color(0xff1c1e22),
|
||||||
|
this.whiteSmoke = const Color(0xff13151b),
|
||||||
|
this.whiteSnow = const Color(0xff070A0D),
|
||||||
|
this.white = const Color(0xff101418),
|
||||||
|
this.blueAlice = const Color(0xff00193D),
|
||||||
|
this.accentBlue = const Color(0xff005FFF),
|
||||||
|
this.accentRed = const Color(0xffFF3742),
|
||||||
|
this.accentGreen = const Color(0xff20E070),
|
||||||
|
});
|
||||||
|
|
||||||
|
ColorTheme copyWith({
|
||||||
|
ColorThemeType type = ColorThemeType.light,
|
||||||
|
Color black,
|
||||||
|
Color grey,
|
||||||
|
Color greyGainsboro,
|
||||||
|
Color greyWhisper,
|
||||||
|
Color whiteSmoke,
|
||||||
|
Color whiteSnow,
|
||||||
|
Color white,
|
||||||
|
Color blueAlice,
|
||||||
|
Color accentBlue,
|
||||||
|
Color accentRed,
|
||||||
|
Color accentGreen,
|
||||||
|
}) {
|
||||||
|
return type == ColorThemeType.light
|
||||||
|
? ColorTheme.light(
|
||||||
|
black: black ?? this.black,
|
||||||
|
grey: grey ?? this.grey,
|
||||||
|
greyGainsboro: greyGainsboro ?? this.greyGainsboro,
|
||||||
|
greyWhisper: greyWhisper ?? this.greyWhisper,
|
||||||
|
whiteSmoke: whiteSmoke ?? this.whiteSmoke,
|
||||||
|
whiteSnow: whiteSnow ?? this.whiteSnow,
|
||||||
|
white: white ?? this.white,
|
||||||
|
blueAlice: blueAlice ?? this.blueAlice,
|
||||||
|
accentBlue: accentBlue ?? this.accentBlue,
|
||||||
|
accentRed: accentRed ?? this.accentRed,
|
||||||
|
accentGreen: accentGreen ?? this.accentGreen,
|
||||||
|
)
|
||||||
|
: ColorTheme.dark(
|
||||||
|
black: black ?? this.black,
|
||||||
|
grey: grey ?? this.grey,
|
||||||
|
greyGainsboro: greyGainsboro ?? this.greyGainsboro,
|
||||||
|
greyWhisper: greyWhisper ?? this.greyWhisper,
|
||||||
|
whiteSmoke: whiteSmoke ?? this.whiteSmoke,
|
||||||
|
whiteSnow: whiteSnow ?? this.whiteSnow,
|
||||||
|
white: white ?? this.white,
|
||||||
|
blueAlice: blueAlice ?? this.blueAlice,
|
||||||
|
accentBlue: accentBlue ?? this.accentBlue,
|
||||||
|
accentRed: accentRed ?? this.accentRed,
|
||||||
|
accentGreen: accentGreen ?? this.accentGreen,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Channel theme data
|
/// Channel theme data
|
||||||
class ChannelTheme {
|
class ChannelTheme {
|
||||||
/// Theme of the [ChannelHeader] widget
|
/// Theme of the [ChannelHeader] widget
|
||||||
|
|||||||
@@ -769,4 +769,28 @@ class StreamSvgIcon extends StatelessWidget {
|
|||||||
height: size,
|
height: size,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
factory StreamSvgIcon.error({
|
||||||
|
double size,
|
||||||
|
Color color,
|
||||||
|
}) {
|
||||||
|
return StreamSvgIcon(
|
||||||
|
assetName: 'Icon_error.svg',
|
||||||
|
color: color,
|
||||||
|
width: size,
|
||||||
|
height: size,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
factory StreamSvgIcon.circle_up({
|
||||||
|
double size,
|
||||||
|
Color color,
|
||||||
|
}) {
|
||||||
|
return StreamSvgIcon(
|
||||||
|
assetName: 'Icon_circle_up.svg',
|
||||||
|
color: color,
|
||||||
|
width: size,
|
||||||
|
height: size,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-13
@@ -51,17 +51,21 @@ class UrlAttachment extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
hostDisplayName,
|
hostDisplayName,
|
||||||
style: TextStyle(
|
style: StreamChatTheme.of(context)
|
||||||
fontWeight: FontWeight.w700,
|
.textTheme
|
||||||
color: Color(0xFF006CFF),
|
.bodyBold
|
||||||
),
|
.copyWith(
|
||||||
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.accentBlue,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.only(
|
borderRadius: BorderRadius.only(
|
||||||
topRight: Radius.circular(16.0),
|
topRight: Radius.circular(16.0),
|
||||||
),
|
),
|
||||||
color: Color(0xFFE9F2FF),
|
color: StreamChatTheme.of(context).colorTheme.blueAlice,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -81,18 +85,18 @@ class UrlAttachment extends StatelessWidget {
|
|||||||
urlAttachment.title.trim(),
|
urlAttachment.title.trim(),
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: TextStyle(
|
style: StreamChatTheme.of(context)
|
||||||
fontWeight: FontWeight.w700,
|
.textTheme
|
||||||
fontSize: 12.0,
|
.body
|
||||||
),
|
.copyWith(fontWeight: FontWeight.w700),
|
||||||
),
|
),
|
||||||
if (urlAttachment.text != null)
|
if (urlAttachment.text != null)
|
||||||
Text(
|
Text(
|
||||||
urlAttachment.text,
|
urlAttachment.text,
|
||||||
style: TextStyle(
|
style: StreamChatTheme.of(context)
|
||||||
fontWeight: FontWeight.w400,
|
.textTheme
|
||||||
fontSize: 12.0,
|
.body
|
||||||
),
|
.copyWith(fontWeight: FontWeight.w400),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class UserAvatar extends StatelessWidget {
|
|||||||
this.borderRadius,
|
this.borderRadius,
|
||||||
this.onlineIndicatorAlignment = Alignment.topRight,
|
this.onlineIndicatorAlignment = Alignment.topRight,
|
||||||
this.selected = false,
|
this.selected = false,
|
||||||
this.selectionColor = const Color(0xFF006CFF),
|
this.selectionColor,
|
||||||
this.selectionThickness = 4,
|
this.selectionThickness = 4,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ class UserAvatar extends StatelessWidget {
|
|||||||
constraints: constraints ??
|
constraints: constraints ??
|
||||||
streamChatTheme.ownMessageTheme.avatarTheme.constraints,
|
streamChatTheme.ownMessageTheme.avatarTheme.constraints,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: streamChatTheme.accentColor,
|
color: streamChatTheme.colorTheme.accentBlue,
|
||||||
),
|
),
|
||||||
child: hasImage
|
child: hasImage
|
||||||
? CachedNetworkImage(
|
? CachedNetworkImage(
|
||||||
@@ -61,13 +61,17 @@ class UserAvatar extends StatelessWidget {
|
|||||||
: streamChatTheme.defaultUserImage(context, user),
|
: streamChatTheme.defaultUserImage(context, user),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (selected) {
|
if (selected) {
|
||||||
avatar = ClipRRect(
|
avatar = ClipRRect(
|
||||||
borderRadius: (borderRadius ??
|
borderRadius: (borderRadius ??
|
||||||
streamChatTheme.ownMessageTheme.avatarTheme.borderRadius) +
|
streamChatTheme.ownMessageTheme.avatarTheme.borderRadius) +
|
||||||
BorderRadius.circular(selectionThickness),
|
BorderRadius.circular(selectionThickness),
|
||||||
child: Container(
|
child: Container(
|
||||||
color: selectionColor,
|
constraints: constraints ??
|
||||||
|
streamChatTheme.ownMessageTheme.avatarTheme.constraints,
|
||||||
|
color: selectionColor ??
|
||||||
|
StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.all(selectionThickness),
|
padding: EdgeInsets.all(selectionThickness),
|
||||||
child: avatar,
|
child: avatar,
|
||||||
@@ -96,10 +100,10 @@ class UserAvatar extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
child: Material(
|
child: Material(
|
||||||
shape: CircleBorder(),
|
shape: CircleBorder(),
|
||||||
color: Color(0xff20E070),
|
color: streamChatTheme.colorTheme.accentGreen,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
color: Colors.white,
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
+11
-5
@@ -74,24 +74,30 @@ class UserItem extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
trailing: selected
|
trailing: selected
|
||||||
? CircleAvatar(
|
? CircleAvatar(
|
||||||
|
backgroundColor:
|
||||||
|
StreamChatTheme.of(context).colorTheme.accentBlue,
|
||||||
child: StreamSvgIcon.check(
|
child: StreamSvgIcon.check(
|
||||||
size: 20,
|
size: 20,
|
||||||
color: Colors.white,
|
color: StreamChatTheme.of(context).colorTheme.white,
|
||||||
),
|
),
|
||||||
radius: 10,
|
radius: 10,
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
title: Text(
|
title: Text(
|
||||||
user.name,
|
user.name,
|
||||||
style: TextStyle(fontWeight: FontWeight.bold),
|
style: StreamChatTheme.of(context).textTheme.bodyBold,
|
||||||
),
|
),
|
||||||
subtitle: showLastOnline ? _buildLastActive(context) : null,
|
subtitle: showLastOnline ? _buildLastActive(context) : null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildLastActive(context) {
|
Widget _buildLastActive(context) {
|
||||||
return user.online == true
|
return Text(
|
||||||
? Text('Online')
|
user.online == true
|
||||||
: Text('Last online ${Jiffy(user.lastActive).fromNow()}');
|
? 'Online'
|
||||||
|
: 'Last online ${Jiffy(user.lastActive).fromNow()}',
|
||||||
|
style: StreamChatTheme.of(context).textTheme.footnote.copyWith(
|
||||||
|
color: StreamChatTheme.of(context).colorTheme.black.withOpacity(.5)),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -356,15 +356,19 @@ class _UserListViewState extends State<UserListView>
|
|||||||
headerItem: (header) {
|
headerItem: (header) {
|
||||||
return Container(
|
return Container(
|
||||||
key: ValueKey<String>('HEADER-$header'),
|
key: ValueKey<String>('HEADER-$header'),
|
||||||
color: Colors.black.withOpacity(0.05),
|
color:
|
||||||
|
StreamChatTheme.of(context).colorTheme.black.withOpacity(0.05),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 6),
|
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 6),
|
||||||
child: Text(
|
child: Text(
|
||||||
header,
|
header,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 12,
|
fontSize: 14.5,
|
||||||
color: Colors.black.withOpacity(0.3)),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(0.3)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -449,7 +453,10 @@ class _UserListViewState extends State<UserListView>
|
|||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
if (snapshot.hasError) {
|
if (snapshot.hasError) {
|
||||||
return Container(
|
return Container(
|
||||||
color: Color(0xffd0021B).withAlpha(26),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.accentRed
|
||||||
|
.withOpacity(.2),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||||
child: Center(
|
child: Center(
|
||||||
@@ -472,8 +479,8 @@ class _UserListViewState extends State<UserListView>
|
|||||||
return Container(
|
return Container(
|
||||||
height: 1,
|
height: 1,
|
||||||
color: Theme.of(context).brightness == Brightness.dark
|
color: Theme.of(context).brightness == Brightness.dark
|
||||||
? Colors.white.withOpacity(0.1)
|
? StreamChatTheme.of(context).colorTheme.white.withOpacity(0.1)
|
||||||
: Colors.black.withOpacity(0.1),
|
: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.1),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
-4
@@ -27,7 +27,7 @@ Future<bool> showConfirmationDialog(
|
|||||||
String cancelText,
|
String cancelText,
|
||||||
}) {
|
}) {
|
||||||
return showModalBottomSheet(
|
return showModalBottomSheet(
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: StreamChatTheme.of(context).colorTheme.white,
|
||||||
context: context,
|
context: context,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.only(
|
borderRadius: BorderRadius.only(
|
||||||
@@ -47,7 +47,7 @@ Future<bool> showConfirmationDialog(
|
|||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
title,
|
title,
|
||||||
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16.0),
|
style: StreamChatTheme.of(context).textTheme.headlineBold,
|
||||||
),
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 7.0,
|
height: 7.0,
|
||||||
@@ -57,7 +57,8 @@ Future<bool> showConfirmationDialog(
|
|||||||
height: 36.0,
|
height: 36.0,
|
||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
color: Color(0xffe6e6e6),
|
color:
|
||||||
|
StreamChatTheme.of(context).colorTheme.black.withOpacity(.08),
|
||||||
height: 1.0,
|
height: 1.0,
|
||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
@@ -67,7 +68,10 @@ Future<bool> showConfirmationDialog(
|
|||||||
child: Text(
|
child: Text(
|
||||||
cancelText,
|
cancelText,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.black.withOpacity(0.5),
|
color: StreamChatTheme.of(context)
|
||||||
|
.colorTheme
|
||||||
|
.black
|
||||||
|
.withOpacity(0.5),
|
||||||
fontWeight: FontWeight.w400),
|
fontWeight: FontWeight.w400),
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
|
|||||||
Reference in New Issue
Block a user