diff --git a/analysis_options.yaml b/analysis_options.yaml index 8d6f9064..42965ec7 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,63 +1,63 @@ -include: package:pedantic/analysis_options.yaml - -analyzer: - enable-experiment: - - extension-methods - exclude: - - lib/**/*.g.dart - - example/** - -linter: - rules: - # these rules are documented on and in the same order as - # the Dart Lint rules page to make maintenance easier - # https://github.com/dart-lang/linter/blob/master/example/all.yaml - # - always_declare_return_types - # - always_specify_types - # - annotate_overrides - # - avoid_as - - avoid_empty_else - - avoid_init_to_null - - avoid_return_types_on_setters - - avoid_web_libraries_in_flutter - - await_only_futures - - camel_case_types - - cancel_subscriptions - - close_sinks - # - comment_references # we do not presume as to what people want to reference in their dartdocs - # - constant_identifier_names # https://github.com/dart-lang/linter/issues/204 - - control_flow_in_finally - - empty_constructor_bodies - - empty_statements - - hash_and_equals - - implementation_imports - # - invariant_booleans - # - iterable_contains_unrelated_type - - library_names - # - library_prefixes - # - list_remove_unrelated_type - # - literal_only_boolean_expressions - - non_constant_identifier_names - # - one_member_abstracts - # - only_throw_errors - # - overridden_fields -# - package_api_docs - - package_names - - package_prefixed_library_names - - prefer_is_not_empty - # - prefer_mixin # https://github.com/dart-lang/language/issues/32 - - public_member_api_docs - - slash_for_doc_comments - # - sort_constructors_first - # - sort_unnamed_constructors_first - # - super_goes_last # no longer needed w/ Dart 2 - - test_types_in_equals - - throw_in_finally - # - type_annotate_public_apis # subset of always_specify_types - - type_init_formals - # - unawaited_futures - - unnecessary_brace_in_string_interps - - unnecessary_getters_setters - - unnecessary_statements +#include: package:pedantic/analysis_options.yaml +# +#analyzer: +# enable-experiment: +# - extension-methods +# exclude: +# - lib/**/*.g.dart +# - example/** +# +#linter: +# rules: +# # these rules are documented on and in the same order as +# # the Dart Lint rules page to make maintenance easier +# # https://github.com/dart-lang/linter/blob/master/example/all.yaml +# # - always_declare_return_types +# # - always_specify_types +# # - annotate_overrides +# # - avoid_as +# - avoid_empty_else +# - avoid_init_to_null +# - avoid_return_types_on_setters +# - avoid_web_libraries_in_flutter +# - await_only_futures +# - camel_case_types +# - cancel_subscriptions +# - close_sinks +# # - comment_references # we do not presume as to what people want to reference in their dartdocs +# # - constant_identifier_names # https://github.com/dart-lang/linter/issues/204 +# - control_flow_in_finally +# - empty_constructor_bodies +# - empty_statements +# - hash_and_equals +# - implementation_imports +# # - invariant_booleans +# # - iterable_contains_unrelated_type +# - library_names +# # - library_prefixes +# # - list_remove_unrelated_type +# # - literal_only_boolean_expressions +# - non_constant_identifier_names +# # - one_member_abstracts +# # - only_throw_errors +# # - overridden_fields +## - package_api_docs +# - package_names +# - package_prefixed_library_names +# - prefer_is_not_empty +# # - prefer_mixin # https://github.com/dart-lang/language/issues/32 +# - public_member_api_docs +# - slash_for_doc_comments +# # - sort_constructors_first +# # - sort_unnamed_constructors_first +# # - super_goes_last # no longer needed w/ Dart 2 +# - test_types_in_equals +# - throw_in_finally +# # - type_annotate_public_apis # subset of always_specify_types +# - type_init_formals +# # - unawaited_futures +# - unnecessary_brace_in_string_interps +# - unnecessary_getters_setters +# - unnecessary_statements - unrelated_type_equality_checks - valid_regexps diff --git a/example/ios/Flutter/.last_build_id b/example/ios/Flutter/.last_build_id index e72273c3..f57e1e1f 100644 --- a/example/ios/Flutter/.last_build_id +++ b/example/ios/Flutter/.last_build_id @@ -1 +1 @@ -13a41b8138c4868054e44b5158f3bdd6 \ No newline at end of file +c770358a10272b4ee1cdc2eb432445f6 \ No newline at end of file diff --git a/example/lib/advanced_options_page.dart b/example/lib/advanced_options_page.dart index e07afefd..483e0902 100644 --- a/example/lib/advanced_options_page.dart +++ b/example/lib/advanced_options_page.dart @@ -3,12 +3,12 @@ import 'dart:io'; import 'package:example/stream_version.dart'; import 'package:flutter/foundation.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 'choose_user_page.dart'; import 'main.dart'; import 'notifications_service.dart'; -import 'choose_user_page.dart'; -import 'package:flutter_secure_storage/flutter_secure_storage.dart'; class AdvancedOptionsPage extends StatefulWidget { @override @@ -34,20 +34,23 @@ class _AdvancedOptionsPageState extends State { @override Widget build(BuildContext context) { return Scaffold( + backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, resizeToAvoidBottomPadding: false, appBar: AppBar( - backgroundColor: StreamChatTheme.of(context).primaryColor, + backgroundColor: StreamChatTheme.of(context).colorTheme.white, elevation: 1, centerTitle: true, + brightness: Theme.of(context).brightness, title: Text( 'Advanced Options', - style: Theme.of(context).textTheme.subtitle1.copyWith( - fontWeight: FontWeight.bold, - ), + style: StreamChatTheme.of(context) + .textTheme + .headlineBold + .copyWith(color: StreamChatTheme.of(context).colorTheme.black), ), leading: IconButton( icon: StreamSvgIcon.left( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), onPressed: () { Navigator.pop(context); @@ -87,7 +90,7 @@ class _AdvancedOptionsPageState extends State { }, style: TextStyle( fontSize: 14, - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), decoration: InputDecoration( errorStyle: TextStyle(fontSize: 0), @@ -95,14 +98,18 @@ class _AdvancedOptionsPageState extends State { fontSize: 14, fontWeight: FontWeight.bold, color: _apiKeyError != null - ? Color(0xffff3742) - : Colors.black.withOpacity(.5), + ? StreamChatTheme.of(context).colorTheme.accentRed + : StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5), ), border: UnderlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: BorderSide.none, ), - fillColor: Color(0xffF5F5F5), + fillColor: + StreamChatTheme.of(context).colorTheme.whiteSmoke, filled: true, labelText: 'Chat API Key ${_apiKeyError != null ? ':$_apiKeyError' : ''}', @@ -131,7 +138,7 @@ class _AdvancedOptionsPageState extends State { }, style: TextStyle( fontSize: 14, - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), textInputAction: TextInputAction.next, decoration: InputDecoration( @@ -140,14 +147,18 @@ class _AdvancedOptionsPageState extends State { fontWeight: FontWeight.bold, fontSize: 14, color: _userIdError != null - ? Color(0xffff3742) - : Colors.black.withOpacity(.5), + ? StreamChatTheme.of(context).colorTheme.accentRed + : StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5), ), border: UnderlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: BorderSide.none, ), - fillColor: Color(0xffF5F5F5), + fillColor: + StreamChatTheme.of(context).colorTheme.whiteSmoke, filled: true, labelText: 'User ID ${_userIdError != null ? ':$_userIdError' : ''}', @@ -176,7 +187,7 @@ class _AdvancedOptionsPageState extends State { }, style: TextStyle( fontSize: 14, - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), textInputAction: TextInputAction.next, decoration: InputDecoration( @@ -185,14 +196,18 @@ class _AdvancedOptionsPageState extends State { fontWeight: FontWeight.bold, fontSize: 14, color: _userTokenError != null - ? Color(0xffff3742) - : Colors.black.withOpacity(.5), + ? StreamChatTheme.of(context).colorTheme.accentRed + : StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5), ), border: UnderlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: BorderSide.none, ), - fillColor: Color(0xffF5F5F5), + fillColor: + StreamChatTheme.of(context).colorTheme.whiteSmoke, filled: true, labelText: 'User Token ${_userTokenError != null ? ':$_userTokenError' : ''}', @@ -208,13 +223,17 @@ class _AdvancedOptionsPageState extends State { labelStyle: TextStyle( fontSize: 14, fontWeight: FontWeight.bold, - color: Colors.black.withOpacity(.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5), ), border: UnderlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: BorderSide.none, ), - fillColor: Color(0xffF5F5F5), + fillColor: + StreamChatTheme.of(context).colorTheme.whiteSmoke, filled: true, labelText: 'Username (optional)', ), @@ -224,13 +243,14 @@ class _AdvancedOptionsPageState extends State { child: Align( alignment: Alignment.bottomCenter, child: FlatButton( - color: StreamChatTheme.of(context).accentColor, + color: + StreamChatTheme.of(context).colorTheme.accentBlue, minWidth: double.infinity, height: 48, child: Text( 'Login', style: TextStyle( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, fontSize: 16, ), ), @@ -255,7 +275,9 @@ class _AdvancedOptionsPageState extends State { child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(16), - color: Colors.white, + color: StreamChatTheme.of(context) + .colorTheme + .white, ), height: 100, width: 100, diff --git a/example/lib/chips_input_text_field.dart b/example/lib/chips_input_text_field.dart index 2ef308f8..7291ef03 100644 --- a/example/lib/chips_input_text_field.dart +++ b/example/lib/chips_input_text_field.dart @@ -66,7 +66,7 @@ class ChipInputTextFieldState extends State> { onTap: _pauseItemAddition ? resumeItemAddition : null, child: Material( elevation: 1, - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, child: Container( child: Padding( padding: const EdgeInsets.fromLTRB(16, 16, 16, 16), @@ -78,10 +78,14 @@ class ChipInputTextFieldState extends State> { padding: const EdgeInsets.symmetric(vertical: 4.0), child: Text( 'TO:', - style: TextStyle( - fontSize: 12, - color: Colors.black.withOpacity(0.5), - ), + style: StreamChatTheme.of(context) + .textTheme + .footnote + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5)), ), ), SizedBox(width: 12), @@ -111,10 +115,14 @@ class ChipInputTextFieldState extends State> { disabledBorder: InputBorder.none, contentPadding: const EdgeInsets.only(top: 4.0), hintText: widget.hint, - hintStyle: TextStyle( - color: Colors.black.withOpacity(0.5), - fontSize: 14, - ), + hintStyle: StreamChatTheme.of(context) + .textTheme + .body + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5)), ), ), ], @@ -126,11 +134,17 @@ class ChipInputTextFieldState extends State> { child: IconButton( icon: _chips.isEmpty ? StreamSvgIcon.user( - color: Colors.black.withOpacity(0.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), size: 24, ) : StreamSvgIcon.userAdd( - color: Colors.black.withOpacity(0.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), size: 24, ), onPressed: resumeItemAddition, diff --git a/example/lib/choose_user_page.dart b/example/lib/choose_user_page.dart index a64013b9..55bfa36c 100644 --- a/example/lib/choose_user_page.dart +++ b/example/lib/choose_user_page.dart @@ -1,5 +1,3 @@ -import 'package:example/advanced_options_page.dart'; -import 'package:example/main.dart'; import 'package:example/stream_version.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -60,6 +58,7 @@ class ChooseUserPage extends StatelessWidget { (_, value) => value..extraData['image'] = getRandomPicUrl(value)); return Scaffold( + backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, body: SafeArea( child: Column( crossAxisAlignment: CrossAxisAlignment.center, @@ -80,19 +79,12 @@ class ChooseUserPage extends StatelessWidget { padding: const EdgeInsets.only(bottom: 13.0), child: Text( 'Welcome to Stream Chat', - style: TextStyle( - fontSize: 22, - color: Colors.black, - fontWeight: FontWeight.bold, - ), + style: StreamChatTheme.of(context).textTheme.title, ), ), Text( 'Select a user to try the Flutter SDK:', - style: TextStyle( - fontSize: 14.5, - color: Colors.black, - ), + style: StreamChatTheme.of(context).textTheme.body, ), Expanded( child: Padding( @@ -120,7 +112,9 @@ class ChooseUserPage extends StatelessWidget { child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(16), - color: Colors.white, + color: StreamChatTheme.of(context) + .colorTheme + .white, ), height: 100, width: 100, @@ -169,9 +163,20 @@ class ChooseUserPage extends StatelessWidget { ), title: Text( 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( 'assets/icon_arrow_right.svg', height: 24, @@ -185,16 +190,26 @@ class ChooseUserPage extends StatelessWidget { }, leading: CircleAvatar( child: StreamSvgIcon.settings( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), - backgroundColor: - StreamChatTheme.of(context).secondaryColor, + backgroundColor: StreamChatTheme.of(context) + .colorTheme + .greyWhisper, ), title: Text( '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( 'assets/icon_arrow_right.svg', height: 24, diff --git a/example/lib/custom_theme.dart b/example/lib/custom_theme.dart index 21db1c6c..90635993 100644 --- a/example/lib/custom_theme.dart +++ b/example/lib/custom_theme.dart @@ -50,9 +50,10 @@ class MyApp extends StatelessWidget { client: client, streamChatThemeData: StreamChatThemeData.fromTheme(theme).copyWith( ownMessageTheme: MessageTheme( - messageBackgroundColor: Colors.black, + messageBackgroundColor: + StreamChatTheme.of(context).colorTheme.black, messageText: TextStyle( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, ), avatarTheme: AvatarTheme( borderRadius: BorderRadius.circular(8), diff --git a/example/lib/customize_channel_preview.dart b/example/lib/customize_channel_preview.dart index 3809f780..29d22a82 100644 --- a/example/lib/customize_channel_preview.dart +++ b/example/lib/customize_channel_preview.dart @@ -84,10 +84,12 @@ class ChannelListPage extends StatelessWidget { channel: channel, ), title: ChannelName( - channel: channel, textStyle: StreamChatTheme.of(context).channelPreviewTheme.title.copyWith( - color: Colors.black.withOpacity(opacity), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(opacity), ), ), subtitle: Text(subtitle), diff --git a/example/lib/customize_message_widget.dart b/example/lib/customize_message_widget.dart index fc614125..a3713b69 100644 --- a/example/lib/customize_message_widget.dart +++ b/example/lib/customize_message_widget.dart @@ -127,7 +127,6 @@ class ChannelPage extends StatelessWidget { showTimestamp: !details.isNextUser, showUsername: !details.isNextUser, showReactions: false, - showReplyIndicator: false, ); } } diff --git a/example/lib/group_chat_details_screen.dart b/example/lib/group_chat_details_screen.dart index c6d4331d..03b4877b 100644 --- a/example/lib/group_chat_details_screen.dart +++ b/example/lib/group_chat_details_screen.dart @@ -59,15 +59,16 @@ class _GroupChatDetailsScreenState extends State { return false; }, child: Scaffold( - backgroundColor: Color.fromRGBO(252, 252, 252, 1), + backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, appBar: AppBar( + brightness: Theme.of(context).brightness, elevation: 1, - backgroundColor: Colors.white, + backgroundColor: StreamChatTheme.of(context).colorTheme.white, leading: const StreamBackButton(), title: Text( 'Name of Group Chat', style: TextStyle( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, fontSize: 16, ), ), @@ -82,7 +83,10 @@ class _GroupChatDetailsScreenState extends State { 'NAME', style: TextStyle( fontSize: 12, - color: Colors.black.withOpacity(0.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), ), ), SizedBox(width: 16), @@ -99,7 +103,11 @@ class _GroupChatDetailsScreenState extends State { contentPadding: const EdgeInsets.all(0), hintText: 'Choose a group chat name', 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 { padding: const EdgeInsets.all(0), icon: StreamSvgIcon.check( size: 24, - color: _isGroupNameEmpty ? Colors.grey : Color(0xFF006CFF), + color: _isGroupNameEmpty + ? Colors.grey + : StreamChatTheme.of(context).colorTheme.accentBlue, ), onPressed: _isGroupNameEmpty ? null @@ -144,7 +154,16 @@ class _GroupChatDetailsScreenState extends State { children: [ Container( 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( padding: const EdgeInsets.symmetric( vertical: 8, @@ -167,16 +186,28 @@ class _GroupChatDetailsScreenState extends State { separatorBuilder: (_, __) => Container( height: 1, color: Theme.of(context).brightness == Brightness.dark - ? Colors.white.withOpacity(0.1) - : Colors.black.withOpacity(0.1), + ? StreamChatTheme.of(context) + .colorTheme + .white + .withOpacity(0.1) + : StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.1), ), itemBuilder: (_, index) { if (index == _selectedUsers.length) { return Container( height: 1, color: Theme.of(context).brightness == Brightness.dark - ? Colors.white.withOpacity(0.1) - : Colors.black.withOpacity(0.1), + ? StreamChatTheme.of(context) + .colorTheme + .white + .withOpacity(0.1) + : StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.1), ); } final user = _selectedUsers[index]; @@ -200,7 +231,7 @@ class _GroupChatDetailsScreenState extends State { trailing: IconButton( icon: Icon( Icons.clear_rounded, - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), padding: const EdgeInsets.all(0), splashRadius: 24, diff --git a/example/lib/main.dart b/example/lib/main.dart index 803df8e6..018b2cab 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,8 +1,7 @@ +import 'dart:async'; import 'dart:io'; 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/foundation.dart'; import 'package:flutter/material.dart'; @@ -13,7 +12,6 @@ import 'notifications_service.dart'; import 'routes/app_routes.dart'; import 'routes/routes.dart'; import 'search_text_field.dart'; -import 'dart:async'; void main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -27,7 +25,7 @@ void main() async { logLevel: Level.INFO, showLocalNotification: (!kIsWeb && Platform.isAndroid) ? showLocalNotification : null, - persistenceEnabled: true, + persistenceEnabled: false, ); if (userId != null) { @@ -51,18 +49,20 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { - return StreamChat( - client: client, - child: MaterialApp( - debugShowCheckedModeBanner: false, - theme: ThemeData.light(), - darkTheme: ThemeData.dark(), - //TODO change to system once dark theme is implemented - themeMode: ThemeMode.light, - onGenerateRoute: AppRoutes.generateRoute, - initialRoute: - client.state.user == null ? Routes.CHOOSE_USER : Routes.HOME, - ), + return MaterialApp( + builder: (context, child) { + return StreamChat( + client: client, + child: child, + ); + }, + debugShowCheckedModeBanner: false, + theme: ThemeData.light(), + darkTheme: ThemeData.dark(), + themeMode: ThemeMode.dark, + onGenerateRoute: AppRoutes.generateRoute, + initialRoute: + client.state.user == null ? Routes.CHOOSE_USER : Routes.HOME, ); } } @@ -84,7 +84,9 @@ class _HomePageState extends State { overflow: Overflow.visible, children: [ StreamSvgIcon.message( - color: _isSelected(0) ? Colors.black : Colors.grey, + color: _isSelected(0) + ? StreamChatTheme.of(context).colorTheme.black + : Colors.grey, ), Positioned( top: -3, @@ -100,7 +102,9 @@ class _HomePageState extends State { overflow: Overflow.visible, children: [ StreamSvgIcon.mentions( - color: _isSelected(1) ? Colors.black : Colors.grey, + color: _isSelected(1) + ? StreamChatTheme.of(context).colorTheme.black + : Colors.grey, ), ], ), @@ -113,6 +117,7 @@ class _HomePageState extends State { Widget build(BuildContext context) { final user = StreamChat.of(context).user; return Scaffold( + backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, appBar: ChannelListHeader( onNewChatButtonTap: () { Navigator.pushNamed(context, Routes.NEW_CHAT); @@ -121,10 +126,14 @@ class _HomePageState extends State { drawer: _buildDrawer(context, user), drawerEdgeDragWidth: 50, bottomNavigationBar: BottomNavigationBar( + backgroundColor: StreamChatTheme.of(context).colorTheme.white, currentIndex: _currentIndex, items: _navBarItems, + selectedLabelStyle: StreamChatTheme.of(context).textTheme.footnoteBold, + unselectedLabelStyle: + StreamChatTheme.of(context).textTheme.footnoteBold, type: BottomNavigationBarType.fixed, - selectedItemColor: Colors.black, + selectedItemColor: StreamChatTheme.of(context).colorTheme.black, unselectedItemColor: Colors.grey, onTap: (index) { setState(() => _currentIndex = index); @@ -142,104 +151,116 @@ class _HomePageState extends State { Drawer _buildDrawer(BuildContext context, User user) { return Drawer( - child: SafeArea( - child: Padding( - padding: EdgeInsets.only( - top: MediaQuery.of(context).viewPadding.top + 8, - ), - child: Column( - children: [ - Padding( - padding: const EdgeInsets.only( - bottom: 20.0, - left: 8, + child: Container( + color: StreamChatTheme.of(context).colorTheme.white, + child: SafeArea( + child: Padding( + padding: EdgeInsets.only( + top: MediaQuery.of(context).viewPadding.top + 8, + ), + child: Column( + children: [ + Padding( + 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( - children: [ - UserAvatar( - user: user, - showOnlineStatus: false, - constraints: BoxConstraints.tight(Size.fromRadius(20)), + ListTile( + leading: StreamSvgIcon.penWrite( + color: StreamChatTheme.of(context) + .colorTheme + .black + .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( - user.name, + ), + ), + ListTile( + 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( - fontSize: 16, - fontWeight: FontWeight.bold, + fontSize: 14.5, ), ), ), - ], - ), - ), - 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, - ), - ), - ), - ), - ), - ], + ], + ), ), ), ), @@ -410,7 +431,7 @@ class ChannelPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: Color.fromRGBO(252, 252, 252, 1), + backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, appBar: ChannelHeader( showTypingIndicator: false, ), @@ -435,7 +456,10 @@ class ChannelPage extends StatelessWidget { right: 0, child: Container( alignment: Alignment.centerLeft, - color: Color(0xffFCFCFC).withOpacity(.9), + color: StreamChatTheme.of(context) + .colorTheme + .whiteSnow + .withOpacity(.9), child: TypingIndicator( alignment: Alignment.centerLeft, padding: const EdgeInsets.symmetric( @@ -470,7 +494,7 @@ class ThreadPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: Color.fromRGBO(252, 252, 252, 1), + backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, appBar: ThreadHeader( parent: parent, ), diff --git a/example/lib/new_chat_screen.dart b/example/lib/new_chat_screen.dart index f29b1483..ddebe848 100644 --- a/example/lib/new_chat_screen.dart +++ b/example/lib/new_chat_screen.dart @@ -5,7 +5,6 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'chips_input_text_field.dart'; import 'main.dart'; -import 'new_group_chat_screen.dart'; import 'routes/routes.dart'; class NewChatScreen extends StatefulWidget { @@ -37,8 +36,6 @@ class _NewChatScreenState extends State { bool _showUserList = true; - bool _channelExisted = false; - void _userNameListener() { if (_debounce?.isActive ?? false) _debounce.cancel(); _debounce = Timer(const Duration(milliseconds: 350), () { @@ -122,17 +119,18 @@ class _NewChatScreenState extends State { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: Color.fromRGBO(252, 252, 252, 1), + backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, appBar: AppBar( + brightness: Theme.of(context).brightness, elevation: 0, - backgroundColor: Colors.white, + backgroundColor: StreamChatTheme.of(context).colorTheme.white, leading: const StreamBackButton(), title: Text( 'New Chat', - style: TextStyle( - color: Colors.black, - fontSize: 16, - ), + style: StreamChatTheme.of(context) + .textTheme + .headlineBold + .copyWith(color: StreamChatTheme.of(context).colorTheme.black), ), centerTitle: true, ), @@ -157,7 +155,10 @@ class _NewChatScreenState extends State { children: [ Container( decoration: BoxDecoration( - color: Colors.black.withOpacity(0.05), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.05), borderRadius: BorderRadius.circular(12), ), padding: const EdgeInsets.only(left: 24), @@ -165,7 +166,10 @@ class _NewChatScreenState extends State { padding: const EdgeInsets.fromLTRB(8, 4, 12, 4), child: Text( user.name, - style: TextStyle(color: Colors.black), + style: TextStyle( + color: StreamChatTheme.of(context) + .colorTheme + .black), ), ), ), @@ -182,7 +186,7 @@ class _NewChatScreenState extends State { ), Positioned( child: StreamSvgIcon.close( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, ), ), ], @@ -212,7 +216,9 @@ class _NewChatScreenState extends State { StreamNeumorphicButton( child: Center( child: StreamSvgIcon.contacts( - color: Color(0xFF006CFF), + color: StreamChatTheme.of(context) + .colorTheme + .accentBlue, size: 24, ), ), @@ -220,10 +226,7 @@ class _NewChatScreenState extends State { SizedBox(width: 8), Text( 'Create a Group', - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 16, - ), + style: StreamChatTheme.of(context).textTheme.bodyBold, ), ], ), @@ -238,8 +241,14 @@ class _NewChatScreenState extends State { begin: Alignment.centerLeft, end: Alignment.centerRight, colors: [ - Colors.black.withOpacity(0.02), - Colors.white.withOpacity(0.05), + StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.02), + StreamChatTheme.of(context) + .colorTheme + .white + .withOpacity(0.05), ], stops: [0, 1], ), @@ -250,13 +259,17 @@ class _NewChatScreenState extends State { horizontal: 8, ), child: Text( - _isSearchActive - ? "Matches for \"$_userNameQuery\"" - : 'On the platform', - style: TextStyle( - color: Colors.black.withOpacity(0.5), - ), - ), + _isSearchActive + ? "Matches for \"$_userNameQuery\"" + : 'On the platform', + style: StreamChatTheme.of(context) + .textTheme + .footnote + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5))), ), ), Expanded( @@ -316,7 +329,17 @@ class _NewChatScreenState extends State { ), ), 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 { 'No chats here yet...', style: TextStyle( fontSize: 12, - color: Colors.black.withOpacity(.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5), ), ), ); diff --git a/example/lib/new_group_chat_screen.dart b/example/lib/new_group_chat_screen.dart index ff77e44d..505db69c 100644 --- a/example/lib/new_group_chat_screen.dart +++ b/example/lib/new_group_chat_screen.dart @@ -3,9 +3,8 @@ import 'dart:async'; import 'package:flutter/material.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 'search_text_field.dart'; class NewGroupChatScreen extends StatefulWidget { @override @@ -51,23 +50,24 @@ class _NewGroupChatScreenState extends State { @override Widget build(BuildContext context) { - return SafeArea( - child: Scaffold( - backgroundColor: Color.fromRGBO(252, 252, 252, 1), - body: NestedScrollView( + return Scaffold( + backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, + body: SafeArea( + child: NestedScrollView( floatHeaderSlivers: true, headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { return [ SliverAppBar( + brightness: Theme.of(context).brightness, pinned: true, forceElevated: true, elevation: 1, - backgroundColor: Colors.white, + backgroundColor: StreamChatTheme.of(context).colorTheme.white, leading: const StreamBackButton(), title: Text( 'Add Group Members', style: TextStyle( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, fontSize: 16, ), ), @@ -76,7 +76,8 @@ class _NewGroupChatScreenState extends State { if (_selectedUsers.isNotEmpty) IconButton( icon: StreamSvgIcon.arrow_right( - color: Color(0xFF006CFF), + color: + StreamChatTheme.of(context).colorTheme.accentBlue, ), onPressed: () async { final updatedList = await Navigator.pushNamed( @@ -137,18 +138,21 @@ class _NewGroupChatScreenState extends State { }, child: Container( decoration: BoxDecoration( - color: Colors.white, + color: StreamChatTheme.of(context) + .colorTheme + .white, shape: BoxShape.circle, border: Border.all( - color: Colors.grey.shade100, + color: StreamChatTheme.of(context) + .colorTheme + .whiteSnow, ), ), - child: Padding( - padding: const EdgeInsets.all(0.0), - child: StreamSvgIcon.close( - color: Colors.black, - size: 24, - ), + child: StreamSvgIcon.close( + color: StreamChatTheme.of(context) + .colorTheme + .black, + size: 24, ), ), ), @@ -180,8 +184,14 @@ class _NewGroupChatScreenState extends State { begin: Alignment.centerLeft, end: Alignment.centerRight, colors: [ - Colors.black.withOpacity(0.02), - Colors.white.withOpacity(0.05), + StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.02), + StreamChatTheme.of(context) + .colorTheme + .white + .withOpacity(0.05), ], stops: [0, 1], ), @@ -196,7 +206,10 @@ class _NewGroupChatScreenState extends State { ? 'Matches for \"$_userNameQuery\"' : 'On the platform', 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 { 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( BuildContext context, double shrinkOffset, bool overlapsContent) { return Container( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, child: child, ); } diff --git a/example/lib/search_text_field.dart b/example/lib/search_text_field.dart index e32bb88b..ff34e8a9 100644 --- a/example/lib/search_text_field.dart +++ b/example/lib/search_text_field.dart @@ -22,9 +22,9 @@ class SearchTextField extends StatelessWidget { return Container( height: 36, decoration: BoxDecoration( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, border: Border.all( - color: Colors.grey.shade300, + color: StreamChatTheme.of(context).colorTheme.greyWhisper, ), borderRadius: BorderRadius.circular(24), ), @@ -40,6 +40,7 @@ class SearchTextField extends StatelessWidget { controller: controller, onChanged: onChanged, decoration: InputDecoration( + prefixText: ' ', prefixIconConstraints: BoxConstraints.tight(Size(40, 24)), prefixIcon: Padding( padding: const EdgeInsets.only( @@ -47,15 +48,16 @@ class SearchTextField extends StatelessWidget { right: 8, ), child: StreamSvgIcon.search( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, size: 24, ), ), hintText: hintText, - hintStyle: TextStyle( - color: Colors.black.withOpacity(0.5), - fontSize: 14, - ), + hintStyle: StreamChatTheme.of(context).textTheme.body.copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5)), contentPadding: const EdgeInsets.all(0), border: OutlineInputBorder( borderSide: BorderSide.none, diff --git a/example/lib/stream_version.dart b/example/lib/stream_version.dart index 113e36c0..a3d52ab6 100644 --- a/example/lib/stream_version.dart +++ b/example/lib/stream_version.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:yaml/yaml.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; class StreamVersion extends StatelessWidget { const StreamVersion({ @@ -28,7 +29,8 @@ class StreamVersion extends StatelessWidget { 'Stream SDK v ${streamChatDep}', style: TextStyle( fontSize: 14.5, - color: Colors.black.withOpacity(.13), + color: + StreamChatTheme.of(context).colorTheme.black.withOpacity(.13), ), ); }, diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 175cdaeb..944be796 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.94+97 +version: 1.0.102+105 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/attachment_error.dart b/lib/src/attachment_error.dart index e08867b8..d24423c4 100644 --- a/lib/src/attachment_error.dart +++ b/lib/src/attachment_error.dart @@ -3,6 +3,8 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; +import '../stream_chat_flutter.dart'; + class AttachmentError extends StatelessWidget { final Attachment attachment; final Size size; @@ -23,12 +25,12 @@ class AttachmentError extends StatelessWidget { return Center( child: Container( width: size?.width, - height: size?.height, - color: Color(0xffd0021B).withOpacity(.1), + height: size?.height ?? 200, + color: StreamChatTheme.of(context).colorTheme.accentRed.withOpacity(.1), child: Center( child: Icon( Icons.error_outline, - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.black, ), ), ), diff --git a/lib/src/attachment_title.dart b/lib/src/attachment_title.dart index ab9cd2da..7ed42a59 100644 --- a/lib/src/attachment_title.dart +++ b/lib/src/attachment_title.dart @@ -32,7 +32,7 @@ class AttachmentTitle extends StatelessWidget { attachment.title, overflow: TextOverflow.ellipsis, style: messageTheme.messageText.copyWith( - color: StreamChatTheme.of(context).accentColor, + color: StreamChatTheme.of(context).colorTheme.accentBlue, fontWeight: FontWeight.bold, ), ), diff --git a/lib/src/back_button.dart b/lib/src/back_button.dart index 10b177d2..52adeade 100644 --- a/lib/src/back_button.dart +++ b/lib/src/back_button.dart @@ -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/unread_indicator.dart'; +import '../stream_chat_flutter.dart'; + class StreamBackButton extends StatelessWidget { const StreamBackButton({ Key key, @@ -35,9 +37,7 @@ class StreamBackButton extends StatelessWidget { }, child: StreamSvgIcon.left( size: 24, - color: Theme.of(context).brightness == Brightness.dark - ? Colors.white - : Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), ), ), diff --git a/lib/src/channel_bottom_sheet.dart b/lib/src/channel_bottom_sheet.dart index 2d16bf6d..f4894b02 100644 --- a/lib/src/channel_bottom_sheet.dart +++ b/lib/src/channel_bottom_sheet.dart @@ -73,7 +73,7 @@ class ChannelBottomSheet extends StatelessWidget { ListTile( leading: StreamSvgIcon.userRemove( size: 24, - color: Color(0xff7A7A7A), + color: StreamChatTheme.of(context).colorTheme.grey, ), title: Text( 'Leave Group', @@ -106,13 +106,13 @@ class ChannelBottomSheet extends StatelessWidget { ?.role)) ListTile( leading: StreamSvgIcon.delete( - color: Color(0xFFFF3742), + color: StreamChatTheme.of(context).colorTheme.accentRed, size: 24, ), title: Text( 'Delete chat', style: TextStyle( - color: Color(0xFFFF3742), + color: StreamChatTheme.of(context).colorTheme.accentRed, ), ), onTap: () async { @@ -124,7 +124,7 @@ class ChannelBottomSheet extends StatelessWidget { 'Are you sure you want to delete this conversation?', cancelText: 'CANCEL', icon: StreamSvgIcon.delete( - color: Colors.red, + color: StreamChatTheme.of(context).colorTheme.accentRed, ), ); var channel = StreamChannel.of(context).channel; diff --git a/lib/src/channel_image.dart b/lib/src/channel_image.dart index ad3e930a..2f5862f3 100644 --- a/lib/src/channel_image.dart +++ b/lib/src/channel_image.dart @@ -53,7 +53,7 @@ class ChannelImage extends StatelessWidget { this.showOnlineStatus = true, this.borderRadius, this.selected = false, - this.selectionColor = const Color(0xFF006CFF), + this.selectionColor, this.selectionThickness = 4, }) : super(key: key); @@ -105,7 +105,8 @@ class ChannelImage extends StatelessWidget { .constraints, onTap: onTap != null ? (_) => onTap() : null, selected: selected, - selectionColor: selectionColor, + selectionColor: selectionColor ?? + StreamChatTheme.of(context).colorTheme.accentBlue, selectionThickness: selectionThickness, ); }); @@ -127,7 +128,8 @@ class ChannelImage extends StatelessWidget { .constraints, onTap: onTap, selected: selected, - selectionColor: selectionColor, + selectionColor: selectionColor ?? + StreamChatTheme.of(context).colorTheme.accentBlue, selectionThickness: selectionThickness, ); } @@ -145,7 +147,7 @@ class ChannelImage extends StatelessWidget { .avatarTheme .constraints, decoration: BoxDecoration( - color: StreamChatTheme.of(context).accentColor, + color: StreamChatTheme.of(context).colorTheme.accentBlue, ), child: Stack( alignment: Alignment.center, @@ -161,7 +163,9 @@ class ChannelImage extends StatelessWidget { ? snapshot.data['name'][0] : '', style: TextStyle( - color: Colors.white, + color: StreamChatTheme.of(context) + .colorTheme + .white, fontWeight: FontWeight.bold, ), ), @@ -195,7 +199,8 @@ class ChannelImage extends StatelessWidget { .ownMessageTheme .avatarTheme .constraints, - color: selectionColor, + color: selectionColor ?? + StreamChatTheme.of(context).colorTheme.accentBlue, child: Padding( padding: EdgeInsets.all(selectionThickness), child: child, diff --git a/lib/src/channel_info.dart b/lib/src/channel_info.dart index eda58f43..b1ab568d 100644 --- a/lib/src/channel_info.dart +++ b/lib/src/channel_info.dart @@ -134,7 +134,7 @@ class ChannelInfo extends StatelessWidget { child: Text( 'Try Again', style: textStyle.copyWith( - color: Color(0xFF006CFF), + color: StreamChatTheme.of(context).colorTheme.accentBlue, ), ), ), diff --git a/lib/src/channel_list_header.dart b/lib/src/channel_list_header.dart index 0a01733b..34f3cc76 100644 --- a/lib/src/channel_list_header.dart +++ b/lib/src/channel_list_header.dart @@ -99,7 +99,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { var color; switch (status) { case ConnectionStatus.connected: - color = Color(0xFF006CFF); + color = StreamChatTheme.of(context).colorTheme.accentBlue; break; case ConnectionStatus.connecting: color = Colors.grey; @@ -144,13 +144,8 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { Widget _buildConnectedTitleState(BuildContext context) => Text( 'Stream Chat', - style: StreamChatTheme.of(context) - .channelTheme - .channelHeaderTheme - .title - .copyWith( - fontSize: 16, - fontWeight: FontWeight.bold, + style: StreamChatTheme.of(context).textTheme.headlineBold.copyWith( + color: StreamChatTheme.of(context).colorTheme.black, ), ); @@ -210,7 +205,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { .copyWith( fontSize: 16, fontWeight: FontWeight.bold, - color: Color(0xFF006CFF), + color: StreamChatTheme.of(context).colorTheme.accentBlue, ), ), ), diff --git a/lib/src/channel_list_view.dart b/lib/src/channel_list_view.dart index 5efa1e29..777fae57 100644 --- a/lib/src/channel_list_view.dart +++ b/lib/src/channel_list_view.dart @@ -210,16 +210,18 @@ class _ChannelListViewState extends State padding: const EdgeInsets.all(8.0), child: StreamSvgIcon.message( size: 136, - color: Color(0xffDBDBDB), + color: StreamChatTheme.of(context) + .colorTheme + .greyGainsboro, ), ), Padding( padding: const EdgeInsets.all(8.0), child: Text( 'Let’s start chatting!', - style: TextStyle( - fontSize: 16, - ), + style: StreamChatTheme.of(context) + .textTheme + .headline, ), ), Padding( @@ -230,10 +232,14 @@ class _ChannelListViewState extends State child: Text( 'How about sending your first message to a friend?', textAlign: TextAlign.center, - style: TextStyle( - fontSize: 14, - color: Color(0xff7A7A7A), - ), + style: StreamChatTheme.of(context) + .textTheme + .body + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .grey, + ), ), ), ], @@ -249,11 +255,14 @@ class _ChannelListViewState extends State onPressed: widget.onStartChatPressed, child: Text( 'Start a chat', - style: TextStyle( - color: - StreamChatTheme.of(context).accentColor, - fontWeight: FontWeight.bold, - ), + style: StreamChatTheme.of(context) + .textTheme + .bodyBold + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .accentBlue, + ), ), ), ), @@ -327,8 +336,8 @@ class _ChannelListViewState extends State Shimmer _buildLoadingItem() { if (widget.crossAxisCount > 1) { return Shimmer.fromColors( - baseColor: Color(0xffE5E5E5), - highlightColor: Color(0xffffffff), + baseColor: StreamChatTheme.of(context).colorTheme.greyGainsboro, + highlightColor: StreamChatTheme.of(context).colorTheme.whiteSmoke, child: Column( children: [ SizedBox( @@ -358,12 +367,12 @@ class _ChannelListViewState extends State ); } else { return Shimmer.fromColors( - baseColor: Color(0xffE5E5E5), - highlightColor: Color(0xffffffff), + baseColor: StreamChatTheme.of(context).colorTheme.greyGainsboro, + highlightColor: StreamChatTheme.of(context).colorTheme.whiteSmoke, child: ListTile( leading: Container( decoration: BoxDecoration( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, shape: BoxShape.circle, ), constraints: BoxConstraints.tightFor( @@ -375,7 +384,7 @@ class _ChannelListViewState extends State alignment: Alignment.centerLeft, child: Container( decoration: BoxDecoration( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, borderRadius: BorderRadius.circular(11), ), constraints: BoxConstraints.tightFor( @@ -390,7 +399,7 @@ class _ChannelListViewState extends State alignment: Alignment.centerLeft, child: Container( decoration: BoxDecoration( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, borderRadius: BorderRadius.circular(11), ), constraints: BoxConstraints.tightFor( @@ -402,7 +411,7 @@ class _ChannelListViewState extends State Container( margin: const EdgeInsets.only(left: 16), decoration: BoxDecoration( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, borderRadius: BorderRadius.circular(11), ), constraints: BoxConstraints.tightFor( @@ -536,9 +545,7 @@ class _ChannelListViewState extends State ); } else { final backgroundColor = - Theme.of(context).brightness == Brightness.light - ? Color(0xffEBEBEB) - : Color(0xff141414); + StreamChatTheme.of(context).colorTheme.whiteSmoke; child = Slidable( enabled: widget.swipeToAction, actionPane: SlidableBehindActionPane(), @@ -578,7 +585,7 @@ class _ChannelListViewState extends State IconSlideAction( color: backgroundColor, iconWidget: StreamSvgIcon.delete( - color: Color(0xFFFF3742), + color: StreamChatTheme.of(context).colorTheme.accentRed, ), onTap: () async { final res = await showConfirmationDialog( @@ -589,7 +596,9 @@ class _ChannelListViewState extends State 'Are you sure you want to delete this conversation?', cancelText: 'CANCEL', icon: StreamSvgIcon.delete( - color: Color(0xFFFF3742), + color: StreamChatTheme.of(context) + .colorTheme + .accentRed, ), ); if (res == true) { @@ -599,7 +608,7 @@ class _ChannelListViewState extends State ), ], child: Container( - color: StreamChatTheme.of(context).backgroundColor, + color: StreamChatTheme.of(context).colorTheme.whiteSnow, child: ChannelPreview( onLongPress: widget.onChannelLongPress, channel: channel, @@ -675,7 +684,10 @@ class _ChannelListViewState extends State builder: (context, snapshot) { if (snapshot.hasError) { return Container( - color: Color(0xffd0021B).withAlpha(26), + color: StreamChatTheme.of(context) + .colorTheme + .accentRed + .withOpacity(.2), child: Padding( padding: const EdgeInsets.symmetric(vertical: 16.0), child: Center( @@ -697,9 +709,7 @@ class _ChannelListViewState extends State Widget _separatorBuilder(context, i) { return Container( height: 1, - color: Theme.of(context).brightness == Brightness.dark - ? Colors.white.withOpacity(0.1) - : Colors.black.withOpacity(0.1), + color: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.08), ); } diff --git a/lib/src/channel_preview.dart b/lib/src/channel_preview.dart index d6623544..7b86bf56 100644 --- a/lib/src/channel_preview.dart +++ b/lib/src/channel_preview.dart @@ -50,6 +50,9 @@ class ChannelPreview extends StatelessWidget { return Opacity( opacity: snapshot.data ? 0.5 : 1, child: ListTile( + contentPadding: const EdgeInsets.symmetric( + horizontal: 8, + ), onTap: () { if (onTap != null) { onTap(channel); @@ -131,7 +134,7 @@ class ChannelPreview extends StatelessWidget { .isAfter(channel .state.lastMessage.createdAt)) .length == - (channel.memberCount ?? 0), + ((channel.memberCount ?? 0) - 1), ), ); } diff --git a/lib/src/chat_info_screen.dart b/lib/src/chat_info_screen.dart index 8d291f38..3a9c25ee 100644 --- a/lib/src/chat_info_screen.dart +++ b/lib/src/chat_info_screen.dart @@ -1,4 +1,3 @@ -import 'package:emojis/emojis.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:jiffy/jiffy.dart'; @@ -21,7 +20,7 @@ class _ChatInfoScreenState extends State { Widget build(BuildContext context) { final channel = StreamChannel.of(context).channel; return Scaffold( - backgroundColor: Color(0xFFe6e6e6), + backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, body: ListView( children: [ _buildUserHeader(), @@ -47,7 +46,7 @@ class _ChatInfoScreenState extends State { Widget _buildUserHeader() { return Material( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.whiteSnow, child: SafeArea( child: Stack( children: [ @@ -81,7 +80,11 @@ class _ChatInfoScreenState extends State { child: Text( widget.user.name, style: TextStyle( - color: Colors.black.withOpacity(0.5), fontSize: 16.0), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), + fontSize: 16.0), ), ), onTap: () {}, @@ -92,7 +95,9 @@ class _ChatInfoScreenState extends State { top: 21, left: 16, child: InkWell( - child: StreamSvgIcon.left(), + child: StreamSvgIcon.left( + color: StreamChatTheme.of(context).colorTheme.black, + ), onTap: () { Navigator.of(context).pop(); }, @@ -113,7 +118,7 @@ class _ChatInfoScreenState extends State { // title: 'Notifications', // leading: StreamSvgIcon.Icon_notification( // size: 24.0, - // color: Colors.black.withOpacity(0.5), + // color: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), // ), // trailing: CupertinoSwitch( // value: true, @@ -128,7 +133,10 @@ class _ChatInfoScreenState extends State { title: 'Mute user', leading: StreamSvgIcon.mute( size: 23.0, - color: Colors.black.withOpacity(0.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), ), trailing: snapshot.data == null ? CircularProgressIndicator() @@ -149,7 +157,7 @@ class _ChatInfoScreenState extends State { // title: 'Block User', // leading: StreamSvgIcon.Icon_user_delete( // size: 24.0, - // color: Colors.black.withOpacity(0.5), + // color: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), // ), // trailing: CupertinoSwitch( // value: widget.user.banned, @@ -167,7 +175,8 @@ class _ChatInfoScreenState extends State { title: 'Photos & Videos', leading: StreamSvgIcon.pictures( size: 32.0, - color: Colors.black.withOpacity(0.5), + color: + StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), ), trailing: StreamSvgIcon.right(), onTap: () { @@ -179,7 +188,8 @@ class _ChatInfoScreenState extends State { title: 'Files', leading: StreamSvgIcon.files( size: 32.0, - color: Colors.black.withOpacity(0.5), + color: + StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), ), trailing: StreamSvgIcon.right(), onTap: () { @@ -191,7 +201,8 @@ class _ChatInfoScreenState extends State { title: 'Shared groups', leading: StreamSvgIcon.Icon_group( size: 24.0, - color: Colors.black.withOpacity(0.5), + color: + StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), ), trailing: StreamSvgIcon.right(), onTap: () { @@ -208,7 +219,7 @@ class _ChatInfoScreenState extends State { Widget _buildDeleteListTile() { return _OptionListTile( - title: 'Delete', + title: 'Delete conversation', leading: StreamSvgIcon.delete( color: Colors.red, size: 24.0, @@ -248,12 +259,20 @@ class _ChatInfoScreenState extends State { if (otherMember.online) { alternativeWidget = Text( 'Online', - style: TextStyle(color: Colors.black.withOpacity(0.5)), + style: TextStyle( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5)), ); } else { alternativeWidget = Text( '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 { ), child: Material( shape: CircleBorder(), - color: Color(0xff20E070), + color: StreamChatTheme.of(context).colorTheme.accentGreen, ), ), - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, ), alternativeWidget, ], @@ -303,11 +322,11 @@ class _OptionListTile extends StatelessWidget { return Column( children: [ Container( - color: Color(0xffe6e6e6), + color: StreamChatTheme.of(context).colorTheme.white, height: 2.0, ), Material( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.whiteSnow, child: Container( height: 56.0, child: InkWell( @@ -365,14 +384,16 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> { var chat = StreamChat.of(context); return Scaffold( - backgroundColor: Colors.white, + backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow, appBar: AppBar( brightness: Theme.of(context).brightness, elevation: 1, centerTitle: true, title: Text( 'Shared Groups', - style: TextStyle(color: Colors.black, fontSize: 16.0), + style: TextStyle( + color: StreamChatTheme.of(context).colorTheme.black, + fontSize: 16.0), ), leading: Center( child: InkWell( @@ -381,7 +402,7 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> { }, child: Container( child: StreamSvgIcon.left( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, size: 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>( future: chat.client.queryChannels( @@ -488,7 +509,11 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> { padding: const EdgeInsets.all(8.0), child: Text( '${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( height: 1.0, - color: Color(0xffe6e6e6), + color: + StreamChatTheme.of(context).colorTheme.black.withOpacity(.08), ), ], ); @@ -509,14 +535,16 @@ class _MediaDisplayScreen extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: Colors.white, + backgroundColor: StreamChatTheme.of(context).colorTheme.white, appBar: AppBar( brightness: Theme.of(context).brightness, elevation: 1, centerTitle: true, title: Text( 'Photos & Videos', - style: TextStyle(color: Colors.black, fontSize: 16.0), + style: TextStyle( + color: StreamChatTheme.of(context).colorTheme.black, + fontSize: 16.0), ), leading: Center( child: InkWell( @@ -525,7 +553,7 @@ class _MediaDisplayScreen extends StatelessWidget { }, child: Container( child: StreamSvgIcon.left( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, size: 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 Widget build(BuildContext context) { return Scaffold( - backgroundColor: Colors.white, + backgroundColor: StreamChatTheme.of(context).colorTheme.white, appBar: AppBar( brightness: Theme.of(context).brightness, elevation: 1, centerTitle: true, title: Text( 'Files', - style: TextStyle(color: Colors.black, fontSize: 16.0), + style: TextStyle( + color: StreamChatTheme.of(context).colorTheme.black, + fontSize: 16.0), ), leading: Center( child: InkWell( @@ -559,7 +589,7 @@ class _FileDisplayScreen extends StatelessWidget { }, child: Container( child: StreamSvgIcon.left( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, size: 24.0, ), width: 24.0, @@ -567,7 +597,7 @@ class _FileDisplayScreen extends StatelessWidget { ), ), ), - backgroundColor: StreamChatTheme.of(context).primaryColor, + backgroundColor: StreamChatTheme.of(context).colorTheme.white, ), ); } diff --git a/lib/src/date_divider.dart b/lib/src/date_divider.dart index 8fbe5f77..12070e51 100644 --- a/lib/src/date_divider.dart +++ b/lib/src/date_divider.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.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 class DateDivider extends StatelessWidget { @@ -39,21 +40,17 @@ class DateDivider extends StatelessWidget { child: Container( padding: const EdgeInsets.symmetric(horizontal: 8), decoration: BoxDecoration( - color: (Theme.of(context).brightness == Brightness.light - ? Colors.black - : Colors.white) - .withOpacity(0.5), + color: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), borderRadius: BorderRadius.circular( 8, ), ), child: Text( dayInfo, - style: TextStyle( - fontSize: 12, - color: Colors.white, - fontWeight: FontWeight.bold, - ), + style: StreamChatTheme.of(context).textTheme.footnoteBold.copyWith( + color: StreamChatTheme.of(context).colorTheme.white, + fontWeight: FontWeight.bold, + ), ), ), ); diff --git a/lib/src/deleted_message.dart b/lib/src/deleted_message.dart index 9181d985..5921df43 100644 --- a/lib/src/deleted_message.dart +++ b/lib/src/deleted_message.dart @@ -41,8 +41,14 @@ class DeletedMessage extends StatelessWidget { side: borderSide ?? BorderSide( color: Theme.of(context).brightness == Brightness.dark - ? Colors.white.withAlpha(24) - : Colors.black.withAlpha(24), + ? StreamChatTheme.of(context) + .colorTheme + .white + .withAlpha(24) + : StreamChatTheme.of(context) + .colorTheme + .black + .withAlpha(24), ), ), child: Padding( @@ -58,8 +64,8 @@ class DeletedMessage extends StatelessWidget { style: messageTheme.messageText.copyWith( fontStyle: FontStyle.italic, color: (Theme.of(context).brightness == Brightness.dark - ? Colors.white - : Colors.black) + ? StreamChatTheme.of(context).colorTheme.white + : StreamChatTheme.of(context).colorTheme.black) .withOpacity(.5), ), ), diff --git a/lib/src/file_attachment.dart b/lib/src/file_attachment.dart index 4bba7779..92139530 100644 --- a/lib/src/file_attachment.dart +++ b/lib/src/file_attachment.dart @@ -9,6 +9,7 @@ import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/utils.dart'; import 'package:video_compress/video_compress.dart'; import 'package:video_player/video_player.dart'; + import 'media_utils.dart'; enum FileAttachmentType { local, online } @@ -61,13 +62,13 @@ class _FileAttachmentState extends State { child: Container( width: widget.size?.width ?? 100, height: 56.0, - margin: widget.trailing != null ? EdgeInsets.only(top: 4.0) : null, decoration: BoxDecoration( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, borderRadius: widget.trailing != null ? BorderRadius.circular(16.0) : null, border: widget.trailing != null - ? Border.fromBorderSide(BorderSide(color: Color(0xFFE6E6E6))) + ? Border.fromBorderSide(BorderSide( + color: StreamChatTheme.of(context).colorTheme.greyWhisper)) : null, ), child: Row( @@ -88,10 +89,7 @@ class _FileAttachmentState extends State { children: [ Text( widget.attachment?.title ?? 'File', - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14.0, - ), + style: StreamChatTheme.of(context).textTheme.bodyBold, maxLines: 1, overflow: TextOverflow.ellipsis, ), @@ -100,10 +98,11 @@ class _FileAttachmentState extends State { ), Text( '${_getSizeText(widget.attachment.extraData['file_size'])}', - style: TextStyle( - color: Colors.black.withOpacity(0.5), - fontSize: 14.0, - ), + style: StreamChatTheme.of(context).textTheme.body.copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5)), ), ], ), @@ -113,7 +112,7 @@ class _FileAttachmentState extends State { widget.trailing ?? IconButton( icon: StreamSvgIcon.cloud_download( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), onPressed: () { launchURL(context, widget.attachment.assetUrl); @@ -141,13 +140,13 @@ class _FileAttachmentState extends State { // subtitle: Text( // '${attachment.extraData['file_size'] ?? 'N/A'} bytes', // style: TextStyle( - // color: Colors.black.withOpacity(0.5), + // color: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), // ), // ), // trailing: trailing ?? // IconButton( // icon: StreamSvgIcon.cloud_download( - // color: Colors.black, + // color: StreamChatTheme.of(context).colorTheme.black, // ), // onPressed: () { // launchURL(context, attachment.assetUrl); @@ -179,7 +178,8 @@ class _FileAttachmentState extends State { width: 20.0, height: 20.0, child: CircularProgressIndicator( - backgroundColor: StreamChatTheme.of(context).accentColor, + backgroundColor: + StreamChatTheme.of(context).colorTheme.accentBlue, ), ), ); diff --git a/lib/src/giphy_attachment.dart b/lib/src/giphy_attachment.dart index 3e29b2f1..cc1a319f 100644 --- a/lib/src/giphy_attachment.dart +++ b/lib/src/giphy_attachment.dart @@ -112,7 +112,10 @@ class GiphyAttachment extends StatelessWidget { bottom: 16, left: 16, child: Material( - color: Colors.black.withOpacity(.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), @@ -124,13 +127,16 @@ class GiphyAttachment extends StatelessWidget { child: Row( children: [ StreamSvgIcon.lightning( - color: Colors.white, + color: + StreamChatTheme.of(context).colorTheme.white, size: 16, ), Text( 'GIPHY', style: TextStyle( - color: Colors.white, + color: StreamChatTheme.of(context) + .colorTheme + .white, fontWeight: FontWeight.bold, fontSize: 11, ), @@ -202,7 +208,10 @@ class GiphyAttachment extends StatelessWidget { height: 4.0, ), Container( - color: Colors.black.withOpacity(0.2), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.2), width: double.infinity, height: 0.5, ), @@ -220,15 +229,24 @@ class GiphyAttachment extends StatelessWidget { }, child: Text( 'Cancel', - style: TextStyle( - fontWeight: FontWeight.bold, - color: Colors.black.withOpacity(0.5)), + style: StreamChatTheme.of(context) + .textTheme + .bodyBold + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), + ), ), ), ), Container( width: 0.5, - color: Colors.black.withOpacity(0.2), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.2), height: 50.0, ), Expanded( @@ -242,7 +260,9 @@ class GiphyAttachment extends StatelessWidget { child: Text( 'Send', style: TextStyle( - color: StreamChatTheme.of(context).accentColor, + color: StreamChatTheme.of(context) + .colorTheme + .accentBlue, fontWeight: FontWeight.bold), ), ), @@ -263,7 +283,10 @@ class GiphyAttachment extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ StreamSvgIcon.eye( - color: Colors.black.withOpacity(0.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), size: 16.0, ), SizedBox( @@ -271,10 +294,14 @@ class GiphyAttachment extends StatelessWidget { ), Text( 'Only visible to you', - style: TextStyle( - color: Colors.black.withOpacity(0.5), - fontSize: 12.0, - ), + style: StreamChatTheme.of(context) + .textTheme + .footnote + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5)), ), ], ), @@ -331,7 +358,10 @@ class GiphyAttachment extends StatelessWidget { bottom: 8, left: 8, child: Material( - color: Colors.black.withOpacity(.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), @@ -343,13 +373,13 @@ class GiphyAttachment extends StatelessWidget { child: Row( children: [ StreamSvgIcon.lightning( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, size: 16, ), Text( 'GIPHY', style: TextStyle( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, fontWeight: FontWeight.bold, fontSize: 11, ), diff --git a/lib/src/group_image.dart b/lib/src/group_image.dart index 5f54377d..4cfd655a 100644 --- a/lib/src/group_image.dart +++ b/lib/src/group_image.dart @@ -11,7 +11,7 @@ class GroupImage extends StatelessWidget { this.onTap, this.borderRadius, this.selected = false, - this.selectionColor = const Color(0xFF006CFF), + this.selectionColor, this.selectionThickness = 4, }) : super(key: key); @@ -43,7 +43,7 @@ class GroupImage extends StatelessWidget { .avatarTheme .constraints, decoration: BoxDecoration( - color: StreamChatTheme.of(context).accentColor, + color: StreamChatTheme.of(context).colorTheme.accentBlue, ), child: Flex( direction: Axis.vertical, @@ -110,7 +110,8 @@ class GroupImage extends StatelessWidget { streamChatTheme.ownMessageTheme.avatarTheme.borderRadius) + BorderRadius.circular(selectionThickness), child: Container( - color: selectionColor, + color: selectionColor ?? + StreamChatTheme.of(context).colorTheme.accentBlue, height: 64.0, width: 64.0, child: Padding( diff --git a/lib/src/image_actions_modal.dart b/lib/src/image_actions_modal.dart index fc81635c..168581c0 100644 --- a/lib/src/image_actions_modal.dart +++ b/lib/src/image_actions_modal.dart @@ -1,13 +1,14 @@ import 'dart:typed_data'; import 'dart:ui'; +import 'package:dio/dio.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:dio/dio.dart'; import 'package:image_gallery_saver/image_gallery_saver.dart'; -import '../stream_chat_flutter.dart'; import 'package:path_provider/path_provider.dart'; +import '../stream_chat_flutter.dart'; + class ImageActionsModal extends StatelessWidget { final Message message; final String userName; @@ -66,11 +67,12 @@ class ImageActionsModal extends StatelessWidget { padding: const EdgeInsets.only(top: 8.0), child: Text( userName, - style: TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.w700, - color: Colors.white, - ), + style: StreamChatTheme.of(context) + .textTheme + .headlineBold + .copyWith( + color: + StreamChatTheme.of(context).colorTheme.white), ), ), Text( @@ -78,14 +80,18 @@ class ImageActionsModal extends StatelessWidget { style: StreamChatTheme.of(context) .channelPreviewTheme .subtitle - .copyWith(color: Colors.white.withOpacity(0.5)), + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .white + .withOpacity(0.5)), ), ], ), IconButton( icon: StreamSvgIcon.close( size: 24.0, - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, ), onPressed: () { Navigator.pop(context); @@ -104,10 +110,10 @@ class ImageActionsModal extends StatelessWidget { shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), ), - color: Color(0xffe5e5e5), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: ListTile.divideTiles( + color: StreamChatTheme.of(context).colorTheme.greyWhisper, context: context, tiles: [ _buildButton( @@ -115,7 +121,10 @@ class ImageActionsModal extends StatelessWidget { 'Reply', StreamSvgIcon.Icon_curve_line_left_up( size: 24.0, - color: Colors.black.withOpacity(0.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), ), () {}), _buildButton( @@ -123,7 +132,8 @@ class ImageActionsModal extends StatelessWidget { 'Show in Chat', StreamSvgIcon.eye( size: 24.0, - color: Colors.black, + color: + StreamChatTheme.of(context).colorTheme.black, ), () { Navigator.pop(context); Navigator.pop(context); @@ -133,7 +143,10 @@ class ImageActionsModal extends StatelessWidget { 'Save ${urls[currentIndex].type == 'video' ? 'Video' : 'Image'}', StreamSvgIcon.Icon_save( size: 24.0, - color: Colors.black.withOpacity(0.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), ), () async { var url = urls[currentIndex].imageUrl ?? urls[currentIndex].assetUrl ?? @@ -153,7 +166,9 @@ class ImageActionsModal extends StatelessWidget { 'Delete', StreamSvgIcon.delete( size: 24.0, - color: Color(0xffFF3742), + color: StreamChatTheme.of(context) + .colorTheme + .accentRed, ), () { Navigator.pop(context); @@ -163,7 +178,9 @@ class ImageActionsModal extends StatelessWidget { StreamChannel.of(context).channel.cid, ); }, - color: Color(0xffFF3742), + color: StreamChatTheme.of(context) + .colorTheme + .accentRed, ), ], ).toList(), @@ -182,10 +199,11 @@ class ImageActionsModal extends StatelessWidget { {Color color}) { var titleStyle = TextStyle( fontSize: 14.5, - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ); return Material( + color: StreamChatTheme.of(context).colorTheme.white, child: InkWell( onTap: onTap, child: ListTile( diff --git a/lib/src/image_footer.dart b/lib/src/image_footer.dart index 00b38a90..eff6110a 100644 --- a/lib/src/image_footer.dart +++ b/lib/src/image_footer.dart @@ -5,10 +5,10 @@ import 'dart:typed_data'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:chewie/chewie.dart'; +import 'package:dio/dio.dart'; import 'package:esys_flutter_share/esys_flutter_share.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:dio/dio.dart'; import 'package:image_gallery_saver/image_gallery_saver.dart'; import 'package:path_provider/path_provider.dart'; import 'package:stream_chat/stream_chat.dart'; @@ -114,7 +114,7 @@ class _ImageFooterState extends State { IconButton( icon: StreamSvgIcon.icon_SHARE( size: 24.0, - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), onPressed: () { _buildShareModal(context); @@ -130,11 +130,7 @@ class _ImageFooterState extends State { children: [ Text( '${widget.currentPage + 1} of ${widget.totalPages}', - style: TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.w700, - color: Colors.black, - ), + style: StreamChatTheme.of(context).textTheme.headlineBold, ), ], ), @@ -142,7 +138,7 @@ class _ImageFooterState extends State { ), IconButton( icon: StreamSvgIcon.Icon_grid( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), onPressed: () { _buildPhotosModal(context); @@ -170,7 +166,7 @@ class _ImageFooterState extends State { children: [ Container( decoration: BoxDecoration( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, borderRadius: BorderRadius.only( topRight: Radius.circular(16.0), topLeft: Radius.circular(16.0), @@ -182,11 +178,8 @@ class _ImageFooterState extends State { padding: const EdgeInsets.all(16.0), child: Text( 'Photos', - style: TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.w700, - color: Colors.black, - ), + style: + StreamChatTheme.of(context).textTheme.headlineBold, ), ), ), @@ -194,7 +187,7 @@ class _ImageFooterState extends State { alignment: Alignment.centerRight, child: IconButton( icon: StreamSvgIcon.close( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), onPressed: () { Navigator.pop(context); @@ -205,7 +198,7 @@ class _ImageFooterState extends State { ), ), Container( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, child: GridView.builder( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), @@ -307,7 +300,7 @@ class _ImageFooterState extends State { limit: 25, ), filter: { - if (_searchController.text.isNotEmpty) + if (_channelNameQuery?.trim()?.isNotEmpty == true) 'name': { r'$autocomplete': _channelNameQuery, }, @@ -318,7 +311,7 @@ class _ImageFooterState extends State { sort: [ SortOption( 'name', - direction: 1, + direction: SortOption.ASC, ), ], emptyBuilder: (_) { @@ -360,9 +353,11 @@ class _ImageFooterState extends State { Align( alignment: Alignment.bottomCenter, child: Container( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, height: 48.0, child: Material( + color: + StreamChatTheme.of(context).colorTheme.white, child: InkWell( onTap: () async { var url = widget @@ -392,7 +387,8 @@ class _ImageFooterState extends State { 'Save to Photos', style: TextStyle( color: StreamChatTheme.of(context) - .accentColor, + .colorTheme + .accentBlue, fontWeight: FontWeight.bold, ), ), @@ -429,7 +425,7 @@ class _ImageFooterState extends State { Expanded( child: TextField( controller: _searchController, - cursorColor: Colors.black, + cursorColor: StreamChatTheme.of(context).colorTheme.black, autofocus: true, decoration: InputDecoration( isDense: true, @@ -439,19 +435,25 @@ class _ImageFooterState extends State { padding: const EdgeInsets.symmetric( vertical: 2.0, horizontal: 6.0), child: StreamSvgIcon.search( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), ), hintText: 'Search', border: OutlineInputBorder( borderRadius: BorderRadius.circular(32.0), - borderSide: - BorderSide(color: Colors.black.withOpacity(0.08)), + borderSide: BorderSide( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.08)), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(32.0), - borderSide: - BorderSide(color: Colors.black.withOpacity(0.08)), + borderSide: BorderSide( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.08)), ), contentPadding: EdgeInsets.zero, ), @@ -462,7 +464,10 @@ class _ImageFooterState extends State { ), IconButton( icon: StreamSvgIcon.close_small( - color: Colors.black.withOpacity(0.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), ), onPressed: () { modalSetState(() { @@ -483,7 +488,7 @@ class _ImageFooterState extends State { padding: const EdgeInsets.symmetric(horizontal: 6.0), child: IconButton( icon: StreamSvgIcon.search( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), iconSize: 24.0, onPressed: () { @@ -497,18 +502,14 @@ class _ImageFooterState extends State { padding: const EdgeInsets.all(16.0), child: Text( 'Select a Chat to Share', - style: TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.w700, - color: Colors.black, - ), + style: StreamChatTheme.of(context).textTheme.headlineBold, ), ), Padding( padding: const EdgeInsets.symmetric(horizontal: 6.0), child: IconButton( icon: StreamSvgIcon.share_arrow( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), onPressed: () async { var url = @@ -535,7 +536,7 @@ class _ImageFooterState extends State { return Align( alignment: Alignment.bottomCenter, child: Container( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, height: 56.0, child: _loading ? Center( @@ -566,13 +567,19 @@ class _ImageFooterState extends State { border: OutlineInputBorder( borderRadius: BorderRadius.circular(32.0), borderSide: BorderSide( - color: Colors.black.withOpacity(0.16), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.16), ), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(32.0), borderSide: BorderSide( - color: Colors.black.withOpacity(0.16), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.16), )), contentPadding: EdgeInsets.symmetric(vertical: 12.0), ), @@ -599,7 +606,9 @@ class _ImageFooterState extends State { child: Transform.rotate( angle: -pi / 2, child: StreamSvgIcon.Icon_send_message( - color: StreamChatTheme.of(context).accentColor, + color: StreamChatTheme.of(context) + .colorTheme + .accentBlue, ), ), ), diff --git a/lib/src/image_group.dart b/lib/src/image_group.dart index 44c15623..7bce22f9 100644 --- a/lib/src/image_group.dart +++ b/lib/src/image_group.dart @@ -83,7 +83,9 @@ class ImageGroup extends StatelessWidget { child: Text( '${images.length - 4} +', style: TextStyle( - color: Colors.white, + color: StreamChatTheme.of(context) + .colorTheme + .white, fontSize: 28, ), ), diff --git a/lib/src/image_header.dart b/lib/src/image_header.dart index 62c3f8ec..a9f1173f 100644 --- a/lib/src/image_header.dart +++ b/lib/src/image_header.dart @@ -50,7 +50,7 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget { leading: showBackButton ? IconButton( icon: StreamSvgIcon.close( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, size: 24.0, ), onPressed: onBackPressed, @@ -61,7 +61,7 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget { actions: [ IconButton( icon: StreamSvgIcon.Icon_menu_point_v( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), onPressed: () { _showMessageActionModalBottomSheet(context); @@ -81,11 +81,7 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget { children: [ Text( userName, - style: TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.w700, - color: Colors.black, - ), + style: StreamChatTheme.of(context).textTheme.headlineBold, ), Text( sentAt, diff --git a/lib/src/media_list_view.dart b/lib/src/media_list_view.dart index 5f52e9b5..08ebfcc7 100644 --- a/lib/src/media_list_view.dart +++ b/lib/src/media_list_view.dart @@ -1,10 +1,13 @@ +import 'dart:ui' as ui; + import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.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/stream_svg_icon.dart'; -import 'dart:ui' as ui; + +import '../stream_chat_flutter.dart'; extension on Duration { String format() { @@ -80,7 +83,10 @@ class _MediaListViewState extends State { ? 1.0 : 0.0, child: Container( - color: Colors.black.withOpacity(0.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), alignment: Alignment.topRight, padding: const EdgeInsets.only( top: 8, @@ -88,10 +94,12 @@ class _MediaListViewState extends State { ), child: CircleAvatar( radius: 12, - backgroundColor: Colors.white, + backgroundColor: + StreamChatTheme.of(context).colorTheme.white, child: StreamSvgIcon.check( size: 24, - color: Colors.black, + color: + StreamChatTheme.of(context).colorTheme.black, ), ), ), @@ -113,7 +121,7 @@ class _MediaListViewState extends State { child: Text( media.videoDuration.format(), style: TextStyle( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, ), ), ), @@ -141,7 +149,15 @@ class _MediaListViewState extends State { void _getMedia() async { final assetList = await PhotoManager.getAssetPathList( 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); diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index fad73d93..3bdce507 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -71,7 +71,7 @@ class MessageActionsModal extends StatelessWidget { sigmaY: 10.8731, ), child: Container( - color: Colors.black.withOpacity(0.1), + color: Colors.black.withOpacity(.2), ), ), ), @@ -146,6 +146,9 @@ class MessageActionsModal extends StatelessWidget { horizontal: 48.0, ), child: Material( + color: StreamChatTheme.of(context) + .colorTheme + .whiteSnow, clipBehavior: Clip.hardEdge, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), @@ -248,7 +251,7 @@ class MessageActionsModal extends StatelessWidget { style: Theme.of(context).textTheme.headline6, ), leading: StreamSvgIcon.circle_up( - color: StreamChatTheme.of(context).accentColor, + color: StreamChatTheme.of(context).colorTheme.accentBlue, ), onTap: () { Navigator.pop(context); @@ -270,6 +273,7 @@ class MessageActionsModal extends StatelessWidget { elevation: 2, clipBehavior: Clip.hardEdge, isScrollControlled: true, + backgroundColor: StreamChatTheme.of(context).colorTheme.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.only( topLeft: Radius.circular(32), diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 654aa068..b7416fc5 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -263,7 +263,10 @@ class MessageInputState extends State { border: _sendAsDm ? null : Border.all( - color: Colors.black.withOpacity(.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5), width: 2, ), borderRadius: BorderRadius.circular(3), @@ -272,8 +275,8 @@ class MessageInputState extends State { child: Material( borderRadius: BorderRadius.circular(3), color: _sendAsDm - ? StreamChatTheme.of(context).accentColor - : Colors.white, + ? StreamChatTheme.of(context).colorTheme.accentBlue + : StreamChatTheme.of(context).colorTheme.white, child: InkWell( onTap: () { setState(() { @@ -288,7 +291,7 @@ class MessageInputState extends State { : CrossFadeState.showSecond, firstChild: StreamSvgIcon.check( size: 16.0, - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, ), secondChild: SizedBox( height: 16, @@ -334,7 +337,7 @@ class MessageInputState extends State { child: Padding( padding: const EdgeInsets.all(8.0) + EdgeInsets.only(bottom: 3.0), child: StreamSvgIcon.emptyCircleLeft( - color: StreamChatTheme.of(context).accentColor, + color: StreamChatTheme.of(context).colorTheme.accentBlue, ), ), ), @@ -361,7 +364,7 @@ class MessageInputState extends State { decoration: BoxDecoration( borderRadius: BorderRadius.circular(24.0), border: Border.all( - color: Colors.grey, + color: StreamChatTheme.of(context).colorTheme.greyGainsboro, ), ), padding: _attachments.isEmpty ? null : EdgeInsets.all(6.0), @@ -408,8 +411,9 @@ class MessageInputState extends State { padding: const EdgeInsets.symmetric(horizontal: 8.0), child: Chip( - backgroundColor: - StreamChatTheme.of(context).accentColor, + backgroundColor: StreamChatTheme.of(context) + .colorTheme + .accentBlue, padding: EdgeInsets.zero, labelPadding: EdgeInsets.symmetric(horizontal: 9.0), @@ -418,13 +422,20 @@ class MessageInputState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ StreamSvgIcon.lightning( - color: Colors.white, + color: StreamChatTheme.of(context) + .colorTheme + .white, size: 16.0, ), Text( _chosenCommand?.name?.toUpperCase() ?? "", - style: TextStyle( - color: Colors.white, fontSize: 12.0), + style: StreamChatTheme.of(context) + .textTheme + .footnote + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .white), ), ], ), @@ -602,12 +613,12 @@ class MessageInputState extends State { shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8.0), ), - color: StreamChatTheme.of(context).primaryColor, + color: StreamChatTheme.of(context).colorTheme.white, clipBehavior: Clip.antiAlias, child: Container( constraints: BoxConstraints.loose(Size.fromHeight(400)), decoration: BoxDecoration( - color: StreamChatTheme.of(context).primaryColor, + color: StreamChatTheme.of(context).colorTheme.white, borderRadius: BorderRadius.circular(8.0)), child: ListView( padding: const EdgeInsets.all(0), @@ -625,13 +636,17 @@ class MessageInputState extends State { ), child: StreamSvgIcon.lightning( color: StreamChatTheme.of(context) - .accentColor, + .colorTheme + .accentBlue, ), ), Text( 'Instant Commands', style: TextStyle( - color: Colors.black.withOpacity(.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5), ), ) ], @@ -658,15 +673,6 @@ class MessageInputState extends State { ], ), ), - trailing: CircleAvatar( - backgroundColor: - StreamChatTheme.of(context).accentColor, - child: StreamSvgIcon.lightning( - color: Colors.white, - size: 12.5, - ), - maxRadius: 12, - ), //subtitle: Text(c.description), onTap: () { _setCommand(c); @@ -693,27 +699,36 @@ class MessageInputState extends State { switch (index) { case 0: return _attachments.isEmpty - ? StreamChatTheme.of(context).accentColor + ? StreamChatTheme.of(context).colorTheme.accentBlue : (!_attachmentContainsFile - ? StreamChatTheme.of(context).accentColor - : Colors.black.withOpacity(0.2)); + ? StreamChatTheme.of(context).colorTheme.accentBlue + : StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.2)); break; case 1: return _attachmentContainsFile - ? StreamChatTheme.of(context).accentColor + ? StreamChatTheme.of(context).colorTheme.accentBlue : (_attachments.isEmpty - ? Colors.black.withOpacity(0.5) - : Colors.black.withOpacity(0.2)); + ? StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5) + : StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.2)); break; case 2: return _attachmentContainsFile && _attachments.isNotEmpty - ? Colors.black.withOpacity(0.2) - : Colors.black.withOpacity(0.5); + ? StreamChatTheme.of(context).colorTheme.black.withOpacity(0.2) + : StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5); break; case 3: return _attachmentContainsFile && _attachments.isNotEmpty - ? Colors.black.withOpacity(0.2) - : Colors.black.withOpacity(0.5); + ? StreamChatTheme.of(context).colorTheme.black.withOpacity(0.2) + : StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5); break; } } @@ -722,7 +737,7 @@ class MessageInputState extends State { duration: _animateContainer ? Duration(milliseconds: 300) : Duration.zero, height: _openFilePickerSection ? _filePickerSize : 0, child: Material( - color: Color(0xFFF2F2F2), + color: StreamChatTheme.of(context).colorTheme.whiteSmoke, child: Column( children: [ Row( @@ -789,7 +804,7 @@ class MessageInputState extends State { }, child: Container( decoration: BoxDecoration( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, borderRadius: BorderRadius.only( topLeft: Radius.circular(16.0), topRight: Radius.circular(16.0), @@ -804,7 +819,8 @@ class MessageInputState extends State { width: 40.0, height: 4.0, decoration: BoxDecoration( - color: Color(0xFFF2F2F2), + color: + StreamChatTheme.of(context).colorTheme.whiteSmoke, borderRadius: BorderRadius.circular(4.0), ), ), @@ -817,7 +833,7 @@ class MessageInputState extends State { Expanded( child: Container( decoration: BoxDecoration( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, borderRadius: BorderRadius.circular(8.0), ), child: _buildPickerSection(), @@ -852,11 +868,12 @@ class MessageInputState extends State { }, child: Container( constraints: BoxConstraints.expand(), - color: Color(0xfff2f2f2), + color: StreamChatTheme.of(context).colorTheme.whiteSmoke, child: Text( 'Add more files', style: TextStyle( - color: StreamChatTheme.of(context).accentColor, + color: + StreamChatTheme.of(context).colorTheme.accentBlue, fontWeight: FontWeight.bold, ), ), @@ -885,7 +902,7 @@ class MessageInputState extends State { PhotoManager.openSetting(); }, child: Container( - color: Color(0xFFF2F2F2), + color: StreamChatTheme.of(context).colorTheme.whiteSmoke, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.stretch, @@ -894,16 +911,20 @@ class MessageInputState extends State { 'svgs/icon_picture_empty_state.svg', package: 'stream_chat_flutter', height: 140, - color: StreamChatTheme.of(context).accentColor, + color: + StreamChatTheme.of(context).colorTheme.accentBlue, ), Center( child: Text( 'Allow access to your gallery', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: StreamChatTheme.of(context).accentColor, - ), + style: StreamChatTheme.of(context) + .textTheme + .bodyBold + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .accentBlue, + ), ), ), ], @@ -1019,7 +1040,7 @@ class MessageInputState extends State { CircleAvatar _buildGiphyIcon() { if (kIsWeb) { return CircleAvatar( - backgroundColor: Colors.black, + backgroundColor: StreamChatTheme.of(context).colorTheme.black, child: Image.asset( 'images/giphy_icon.png', package: 'stream_chat_flutter', @@ -1080,7 +1101,7 @@ class MessageInputState extends State { child: Card( margin: EdgeInsets.all(8.0), elevation: 2.0, - color: StreamChatTheme.of(context).primaryColor, + color: StreamChatTheme.of(context).colorTheme.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8.0), ), @@ -1088,7 +1109,7 @@ class MessageInputState extends State { child: Container( constraints: BoxConstraints.loose(Size.fromHeight(400)), decoration: BoxDecoration( - color: StreamChatTheme.of(context).primaryColor, + color: StreamChatTheme.of(context).colorTheme.white, ), child: FutureBuilder>( future: queryMembers ?? Future.value(members), @@ -1116,7 +1137,8 @@ class MessageInputState extends State { subtitle: Text('@${m.userId}'), trailing: StreamSvgIcon.mentions( color: StreamChatTheme.of(context) - .accentColor, + .colorTheme + .accentBlue, ), onTap: () { _mentionedUsers.add(m.user); @@ -1181,7 +1203,7 @@ class MessageInputState extends State { child: Card( margin: EdgeInsets.all(8.0), elevation: 2.0, - color: StreamChatTheme.of(context).primaryColor, + color: StreamChatTheme.of(context).colorTheme.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8.0), ), @@ -1196,7 +1218,7 @@ class MessageInputState extends State { offset: Offset(0, -4), ), ], - color: StreamChatTheme.of(context).primaryColor, + color: StreamChatTheme.of(context).colorTheme.white, ), child: ListView.builder( padding: const EdgeInsets.all(0), @@ -1212,14 +1234,19 @@ class MessageInputState extends State { padding: const EdgeInsets.symmetric(horizontal: 8.0), child: StreamSvgIcon.smile( - color: StreamChatTheme.of(context).accentColor, + color: StreamChatTheme.of(context) + .colorTheme + .accentBlue, ), ), Flexible( child: Text( 'Emoji matching "$query"', style: TextStyle( - color: Colors.black.withOpacity(.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5), ), ), ) @@ -1313,10 +1340,15 @@ class MessageInputState extends State { child: InkWell( child: CircleAvatar( backgroundColor: - Colors.black.withOpacity(0.2), + StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.6), maxRadius: 12.0, child: StreamSvgIcon.close( - color: Colors.white, + color: StreamChatTheme.of(context) + .colorTheme + .white, ), ), onTap: () { @@ -1401,11 +1433,11 @@ class MessageInputState extends State { _attachments.remove(attachment); }); }, - fillColor: Colors.black.withOpacity(.5), + fillColor: StreamChatTheme.of(context).colorTheme.black.withOpacity(.5), child: Center( child: StreamSvgIcon.close( size: 24, - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, ), ), ), @@ -1494,8 +1526,8 @@ class MessageInputState extends State { const EdgeInsets.only(left: 4.0, right: 8.0, top: 8.0, bottom: 8.0), child: StreamSvgIcon.lightning( color: _commandsOverlay != null - ? StreamChatTheme.of(context).accentColor - : Color(0xFF000000).withAlpha(128), + ? StreamChatTheme.of(context).colorTheme.accentBlue + : StreamChatTheme.of(context).colorTheme.grey, ), ), onTap: () async { @@ -1532,8 +1564,8 @@ class MessageInputState extends State { EdgeInsets.only(left: 8.0, right: padding, top: 8.0, bottom: 8.0), child: StreamSvgIcon.attach( color: _openFilePickerSection - ? StreamChatTheme.of(context).accentColor - : Color(0xFF000000).withAlpha(128), + ? StreamChatTheme.of(context).colorTheme.accentBlue + : StreamChatTheme.of(context).colorTheme.grey, ), ), onTap: () async { @@ -1862,7 +1894,7 @@ class MessageInputState extends State { }, child: StreamSvgIcon( assetName: _getIdleSendIcon(), - color: Colors.grey, + color: StreamChatTheme.of(context).colorTheme.greyGainsboro, height: 24.0, width: 24.0, ), @@ -1880,7 +1912,7 @@ class MessageInputState extends State { }, child: StreamSvgIcon( assetName: _getSendIcon(), - color: StreamChatTheme.of(context).accentColor, + color: StreamChatTheme.of(context).colorTheme.accentBlue, height: 24.0, width: 24.0, ), diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index a856db2b..a85beb0a 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -246,16 +246,19 @@ class _MessageListViewState extends State { } final messageList = snapshot.data?.reversed?.toList() ?? []; - if (messageList.isEmpty) { if (_upToDate) { return Center( child: Text( 'No chats here yet...', - style: TextStyle( - fontSize: 12, - color: Colors.black.withOpacity(.5), - ), + style: StreamChatTheme.of(context) + .textTheme + .footnote + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5)), ), ); } @@ -342,8 +345,12 @@ class _MessageListViewState extends State { begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ - Color(0XFFF7F7F7), - Color(0XFFFCFCFC), + StreamChatTheme.of(context) + .colorTheme + .whiteSmoke, + StreamChatTheme.of(context) + .colorTheme + .whiteSnow, ], ), ), @@ -523,9 +530,9 @@ class _MessageListViewState extends State { clipBehavior: Clip.none, children: [ FloatingActionButton( - backgroundColor: Colors.white, + backgroundColor: StreamChatTheme.of(context).colorTheme.white, child: StreamSvgIcon.down( - color: Colors.black, + color: StreamChatTheme.of(context).colorTheme.black, ), onPressed: () { if (unreadCount > 0) { @@ -585,7 +592,10 @@ class _MessageListViewState extends State { builder: (context, snapshot) { if (snapshot.hasError) { return Container( - color: Color(0xffd0021B).withAlpha(26), + color: StreamChatTheme.of(context) + .colorTheme + .accentRed + .withOpacity(.2), child: Center( child: Text('Error loading messages'), ), @@ -839,7 +849,7 @@ class _MessageListViewState extends State { } if (event.message.user.id == streamChannel.channel.client.state.user.id) { WidgetsBinding.instance.addPostFrameCallback((_) { - _scrollController.jumpTo( + _scrollController?.jumpTo( index: 0, ); }); diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index a8701f4d..232f6f84 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -60,7 +60,7 @@ class MessageReactionsModal extends StatelessWidget { sigmaY: 10.8731, ), child: Container( - color: Colors.black.withOpacity(0.1), + color: Colors.black.withOpacity(0.2), ), ), ), @@ -139,6 +139,7 @@ class MessageReactionsModal extends StatelessWidget { horizontal: 8.0, ), child: Card( + color: StreamChatTheme.of(context).colorTheme.white, clipBehavior: Clip.hardEdge, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), diff --git a/lib/src/message_search_item.dart b/lib/src/message_search_item.dart index 35b31aa8..851659e1 100644 --- a/lib/src/message_search_item.dart +++ b/lib/src/message_search_item.dart @@ -126,8 +126,6 @@ class MessageSearchItem extends StatelessWidget { maxLines: 1, overflow: TextOverflow.ellipsis, style: StreamChatTheme.of(context).channelPreviewTheme.subtitle.copyWith( - color: - StreamChatTheme.of(context).channelPreviewTheme.subtitle.color, fontStyle: (message.isSystem || message.isDeleted) ? FontStyle.italic : FontStyle.normal, diff --git a/lib/src/message_search_list_view.dart b/lib/src/message_search_list_view.dart index 087ae839..d59ae4a0 100644 --- a/lib/src/message_search_list_view.dart +++ b/lib/src/message_search_list_view.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/message_search_item.dart'; +import '../stream_chat_flutter.dart'; import 'lazy_load_scroll_view.dart'; import 'message_search_bloc.dart'; @@ -127,8 +128,8 @@ class _MessageSearchListViewState extends State { return Container( height: 1, color: Theme.of(context).brightness == Brightness.dark - ? Colors.white.withOpacity(0.1) - : Colors.black.withOpacity(0.1), + ? StreamChatTheme.of(context).colorTheme.white.withOpacity(0.1) + : StreamChatTheme.of(context).colorTheme.black.withOpacity(0.1), ); } @@ -151,7 +152,10 @@ class _MessageSearchListViewState extends State { builder: (context, snapshot) { if (snapshot.hasError) { return Container( - color: Color(0xffd0021B).withAlpha(26), + color: StreamChatTheme.of(context) + .colorTheme + .accentRed + .withOpacity(.2), child: Padding( padding: const EdgeInsets.symmetric(vertical: 16.0), child: Center( @@ -313,8 +317,14 @@ class _MessageSearchListViewState extends State { begin: Alignment.centerLeft, end: Alignment.centerRight, colors: [ - Colors.black.withOpacity(0.02), - Colors.white.withOpacity(0.05), + StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.02), + StreamChatTheme.of(context) + .colorTheme + .white + .withOpacity(0.05), ], stops: [0, 1], ), @@ -327,7 +337,10 @@ class _MessageSearchListViewState extends State { child: Text( '${items.length} results', style: TextStyle( - color: Colors.black.withOpacity(0.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), ), ), ), diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 9834e097..61c6bf5c 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -346,10 +346,16 @@ class _MessageWidgetState extends State { .brightness == Brightness .dark - ? Colors.white + ? StreamChatTheme.of( + context) + .colorTheme + .white .withAlpha( 24) - : Colors.black + : StreamChatTheme.of( + context) + .colorTheme + .black .withAlpha( 24), ), @@ -438,16 +444,18 @@ class _MessageWidgetState extends State { mainAxisSize: MainAxisSize.min, children: [ StreamSvgIcon.eye( - color: Colors.black.withOpacity(0.5), + color: + StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), size: 16.0, ), SizedBox(width: 8.0), Text( 'Only visible to you', - style: TextStyle( - color: Colors.black.withOpacity(0.5), - fontSize: 12.0, - ), + style: StreamChatTheme.of(context).textTheme.footnote.copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5)), ), ], ), @@ -526,6 +534,7 @@ class _MessageWidgetState extends State { child: CustomPaint( size: const Size(16, 32), painter: _ThreadReplyPainter( + context: context, color: widget.messageTheme.replyThreadColor, ), ), @@ -574,7 +583,7 @@ class _MessageWidgetState extends State { bottom: 0, top: 0, child: Material( - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, clipBehavior: Clip.antiAlias, shape: CircleBorder(), child: Padding( @@ -692,8 +701,8 @@ class _MessageWidgetState extends State { widget.borderSide ?? BorderSide( color: Theme.of(context).brightness == Brightness.dark - ? Colors.white.withAlpha(24) - : Colors.black.withAlpha(24), + ? StreamChatTheme.of(context).colorTheme.white.withAlpha(24) + : StreamChatTheme.of(context).colorTheme.black.withAlpha(24), ), borderRadius: widget.attachmentBorderRadiusGeometry ?? widget.borderRadiusGeometry ?? @@ -807,7 +816,7 @@ class _MessageWidgetState extends State { Text( widget.readList.length.toString(), style: style.copyWith( - color: StreamChatTheme.of(context).accentColor, + color: StreamChatTheme.of(context).colorTheme.accentBlue, ), ), SizedBox(width: 2), @@ -885,7 +894,7 @@ class _MessageWidgetState extends State { if (widget.message.attachments ?.any((element) => element.ogScrapeUrl != null) == true) { - return Color(0xFFE9F2FF); + return StreamChatTheme.of(context).colorTheme.blueAlice; } if (isOnlyEmoji) { @@ -966,13 +975,14 @@ class _MessageWidgetState extends State { class _ThreadReplyPainter extends CustomPainter { final Color color; + final BuildContext context; - const _ThreadReplyPainter({@required this.color}); + const _ThreadReplyPainter({this.context, @required this.color}); @override void paint(Canvas canvas, Size size) { final paint = Paint() - ..color = color ?? Color(0XFFDBDBDB) + ..color = color ?? StreamChatTheme.of(context).colorTheme.greyGainsboro ..style = PaintingStyle.stroke ..strokeWidth = 1 ..strokeCap = StrokeCap.round; diff --git a/lib/src/reaction_bubble.dart b/lib/src/reaction_bubble.dart index 87dc7a92..d8f8c623 100644 --- a/lib/src/reaction_bubble.dart +++ b/lib/src/reaction_bubble.dart @@ -107,16 +107,22 @@ class ReactionBubble extends StatelessWidget { height: 16, color: (!highlightOwnReactions || reaction.user.id == StreamChat.of(context).user.id) - ? StreamChatTheme.of(context).accentColor - : Colors.black.withOpacity(.5), + ? StreamChatTheme.of(context).colorTheme.accentBlue + : StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5), ) : Icon( Icons.help_outline_rounded, size: 16, color: (!highlightOwnReactions || reaction.user.id == StreamChat.of(context).user.id) - ? StreamChatTheme.of(context).accentColor - : Colors.black.withOpacity(.5), + ? StreamChatTheme.of(context).colorTheme.accentBlue + : StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5), ), ); } diff --git a/lib/src/reaction_picker.dart b/lib/src/reaction_picker.dart index b019ee79..5892a66d 100644 --- a/lib/src/reaction_picker.dart +++ b/lib/src/reaction_picker.dart @@ -89,7 +89,9 @@ class _ReactionPickerState extends State height: animations[index].value * 24.0, width: animations[index].value * 24.0, color: ownReactionIndex != -1 - ? StreamChatTheme.of(context).accentColor + ? StreamChatTheme.of(context) + .colorTheme + .accentBlue : Theme.of(context) .iconTheme .color diff --git a/lib/src/sending_indicator.dart b/lib/src/sending_indicator.dart index 34492167..e3a9df06 100644 --- a/lib/src/sending_indicator.dart +++ b/lib/src/sending_indicator.dart @@ -20,7 +20,7 @@ class SendingIndicator extends StatelessWidget { return Icon( Icons.done_all_rounded, size: size, - color: StreamChatTheme.of(context).accentColor, + color: StreamChatTheme.of(context).colorTheme.accentBlue, ); } if (message.status == MessageSendingStatus.SENT || message.status == null) { diff --git a/lib/src/stream_chat.dart b/lib/src/stream_chat.dart index 2763db37..6866b0dd 100644 --- a/lib/src/stream_chat.dart +++ b/lib/src/stream_chat.dart @@ -76,8 +76,8 @@ class StreamChatState extends State with WidgetsBindingObserver { return Theme( data: materialTheme.copyWith( primaryIconTheme: streamTheme.primaryIconTheme, - accentColor: streamTheme.accentColor, - scaffoldBackgroundColor: streamTheme.backgroundColor, + accentColor: streamTheme.colorTheme.accentBlue, + scaffoldBackgroundColor: streamTheme.colorTheme.white, ), child: widget.child, ); @@ -92,11 +92,9 @@ class StreamChatState extends State with WidgetsBindingObserver { ) { final defaultTheme = StreamChatThemeData.getDefaultTheme(Theme.of(context)); final theme = defaultTheme.copyWith( - primaryColor: themeData?.primaryColor, defaultChannelImage: themeData?.defaultChannelImage, primaryIconTheme: themeData?.primaryIconTheme, defaultUserImage: themeData?.defaultUserImage, - backgroundColor: themeData?.backgroundColor, channelTheme: defaultTheme.channelTheme.copyWith( channelHeaderTheme: defaultTheme.channelTheme.channelHeaderTheme.copyWith( @@ -151,8 +149,6 @@ class StreamChatState extends State with WidgetsBindingObserver { reactionsBackgroundColor: themeData?.otherMessageTheme?.reactionsBackgroundColor, ), - accentColor: themeData?.accentColor, - secondaryColor: themeData?.secondaryColor, channelPreviewTheme: defaultTheme.channelPreviewTheme.copyWith( avatarTheme: defaultTheme.channelPreviewTheme.avatarTheme.copyWith( constraints: themeData?.channelPreviewTheme?.avatarTheme?.constraints, diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index a0f552c4..60e37b80 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -42,17 +42,11 @@ class StreamChatTheme extends InheritedWidget { /// Theme data class StreamChatThemeData { - /// Primary color of the chat widgets - final Color primaryColor; + /// The text themes used in the widgets + final TextTheme textTheme; - /// Secondary color of the chat widgets - final Color secondaryColor; - - /// Accent color of the chat widgets - final Color accentColor; - - /// Background color of the chat widgets - final Color backgroundColor; + /// The text themes used in the widgets + final ColorTheme colorTheme; /// Theme of the [ChannelPreview] final ChannelPreviewTheme channelPreviewTheme; @@ -80,10 +74,8 @@ class StreamChatThemeData { /// Create a theme from scratch StreamChatThemeData({ - this.primaryColor, - this.secondaryColor, - this.accentColor, - this.backgroundColor, + this.textTheme, + this.colorTheme, this.channelPreviewTheme, this.channelTheme, this.otherMessageTheme, @@ -99,11 +91,7 @@ class StreamChatThemeData { final defaultTheme = getDefaultTheme(theme); return defaultTheme.copyWith( - accentColor: theme.accentColor, primaryIconTheme: theme.primaryIconTheme, - primaryColor: theme.colorScheme.primary, - secondaryColor: theme.colorScheme.secondary, - backgroundColor: theme.scaffoldBackgroundColor, channelTheme: defaultTheme.channelTheme.copyWith( inputGradient: LinearGradient(colors: [ theme.accentColor.withOpacity(.5), @@ -131,10 +119,8 @@ class StreamChatThemeData { /// Creates a copy of [StreamChatThemeData] with specified attributes overridden. StreamChatThemeData copyWith({ - Color primaryColor, - Color secondaryColor, - Color accentColor, - Color backgroundColor, + TextTheme textTheme, + ColorTheme colorTheme, ChannelPreviewTheme channelPreviewTheme, ChannelTheme channelTheme, MessageTheme ownMessageTheme, @@ -145,24 +131,35 @@ class StreamChatThemeData { List reactionIcons, }) => StreamChatThemeData( - primaryColor: primaryColor ?? this.primaryColor, - secondaryColor: secondaryColor ?? this.secondaryColor, + textTheme: this.textTheme?.copyWith( + 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, - accentColor: accentColor ?? this.accentColor, defaultChannelImage: defaultChannelImage ?? this.defaultChannelImage, defaultUserImage: defaultUserImage ?? this.defaultUserImage, - backgroundColor: backgroundColor ?? this.backgroundColor, - channelPreviewTheme: channelPreviewTheme?.copyWith( - title: - channelPreviewTheme.title ?? this.channelPreviewTheme.title, - subtitle: channelPreviewTheme.subtitle ?? - this.channelPreviewTheme.subtitle, - lastMessageAt: channelPreviewTheme.lastMessageAt ?? - this.channelPreviewTheme.lastMessageAt, - avatarTheme: channelPreviewTheme.avatarTheme ?? - this.channelPreviewTheme.avatarTheme, - ) ?? - this.channelPreviewTheme, + channelPreviewTheme: this.channelPreviewTheme?.copyWith( + title: channelPreviewTheme.title, + subtitle: channelPreviewTheme.subtitle, + lastMessageAt: channelPreviewTheme.lastMessageAt, + avatarTheme: channelPreviewTheme.avatarTheme, + ), channelTheme: channelTheme?.copyWith( channelHeaderTheme: channelTheme.channelHeaderTheme ?? this.channelTheme.channelHeaderTheme, @@ -222,14 +219,13 @@ class StreamChatThemeData { static StreamChatThemeData getDefaultTheme(ThemeData theme) { final accentColor = Color(0xff006cff); final isDark = theme.brightness == Brightness.dark; + final textTheme = isDark ? TextTheme.dark() : TextTheme.light(); + final colorTheme = isDark ? ColorTheme.dark() : ColorTheme.light(); return StreamChatThemeData( - secondaryColor: Color(0xffEAEAEA), - accentColor: accentColor, - primaryColor: isDark ? Colors.black : Colors.white, - primaryIconTheme: IconThemeData( - color: isDark ? Colors.white : Colors.black.withOpacity(.5)), + textTheme: textTheme, + colorTheme: colorTheme, + primaryIconTheme: IconThemeData(color: colorTheme.black.withOpacity(.5)), defaultChannelImage: (context, channel) => SizedBox(), - backgroundColor: isDark ? Colors.black : Colors.white, defaultUserImage: (context, user) => Center( child: CachedNetworkImage( filterQuality: FilterQuality.high, @@ -238,7 +234,7 @@ class StreamChatThemeData { ), ), channelPreviewTheme: ChannelPreviewTheme( - unreadCounterColor: Color(0xffff3742), + unreadCounterColor: colorTheme.accentRed, avatarTheme: AvatarTheme( borderRadius: BorderRadius.circular(20), constraints: BoxConstraints.tightFor( @@ -246,19 +242,12 @@ class StreamChatThemeData { width: 40, ), ), - title: TextStyle( - fontSize: 14, - color: isDark ? Colors.white : Colors.black, - fontWeight: FontWeight.bold), - subtitle: TextStyle( - fontSize: 12.5, - color: (isDark ? Colors.white : Colors.black).withOpacity(0.5), + title: textTheme.bodyBold, + subtitle: textTheme.footnote.copyWith( + color: Color(0xff7A7A7A), ), - lastMessageAt: TextStyle( - fontSize: 11, - color: isDark - ? Colors.white.withOpacity(.5) - : Colors.black.withOpacity(.5), + lastMessageAt: textTheme.footnote.copyWith( + color: colorTheme.black.withOpacity(.5), ), ), channelTheme: ChannelTheme( @@ -273,20 +262,17 @@ class StreamChatThemeData { width: 40, ), ), - color: isDark ? Colors.black : Colors.white, + color: colorTheme.white, title: TextStyle( fontSize: 14, - color: isDark ? Colors.white : Colors.black, + color: colorTheme.black, ), lastMessageAt: TextStyle( fontSize: 11, - color: isDark - ? Colors.white.withOpacity(.5) - : Colors.black.withOpacity(.5), + color: colorTheme.black.withOpacity(.5), ), ), - inputBackground: - isDark ? Colors.black.withAlpha(12) : Colors.white.withAlpha(12), + inputBackground: colorTheme.white.withAlpha(12), inputGradient: LinearGradient(colors: [ Color(0xFF00AEFF), Color(0xFF0076FF), @@ -295,12 +281,10 @@ class StreamChatThemeData { ownMessageTheme: MessageTheme( messageText: TextStyle( fontSize: 14.5, - color: isDark ? Colors.white : Colors.black, + color: colorTheme.black, ), createdAt: TextStyle( - color: isDark - ? Colors.white.withOpacity(.5) - : Colors.black.withOpacity(.5), + color: colorTheme.black.withOpacity(.5), fontSize: 12, ), replies: TextStyle( @@ -308,10 +292,10 @@ class StreamChatThemeData { fontWeight: FontWeight.w600, fontSize: 12, ), - messageBackgroundColor: isDark ? Color(0xff191919) : Color(0xffEAEAEA), - reactionsBackgroundColor: isDark ? Colors.black : Colors.white, - reactionsBorderColor: isDark ? Color(0xff191919) : Color(0xffEAEAEA), - replyThreadColor: isDark ? Color(0xff191919) : Color(0xffEAEAEA), + messageBackgroundColor: colorTheme.greyGainsboro, + reactionsBackgroundColor: colorTheme.white, + reactionsBorderColor: colorTheme.greyWhisper, + replyThreadColor: colorTheme.greyWhisper, avatarTheme: AvatarTheme( borderRadius: BorderRadius.circular(20), constraints: BoxConstraints.tightFor( @@ -324,17 +308,14 @@ class StreamChatThemeData { ), ), otherMessageTheme: MessageTheme( - reactionsBackgroundColor: - isDark ? Color(0xff191919) : Color(0xffEAEAEA), - reactionsBorderColor: isDark ? Colors.black : Colors.white, + reactionsBackgroundColor: colorTheme.greyGainsboro, + reactionsBorderColor: colorTheme.white, messageText: TextStyle( fontSize: 14.5, - color: isDark ? Colors.white : Colors.black, + color: colorTheme.black, ), createdAt: TextStyle( - color: isDark - ? Colors.white.withOpacity(.5) - : Colors.black.withOpacity(.5), + color: colorTheme.black.withOpacity(.5), fontSize: 12, ), replies: TextStyle( @@ -345,9 +326,8 @@ class StreamChatThemeData { messageLinks: TextStyle( color: accentColor, ), - messageBackgroundColor: isDark ? Colors.black : Colors.white, - replyThreadColor: - isDark ? Colors.white.withAlpha(24) : Colors.black.withAlpha(24), + messageBackgroundColor: colorTheme.white, + replyThreadColor: colorTheme.black.withAlpha(24), avatarTheme: AvatarTheme( borderRadius: BorderRadius.circular(20), 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 class ChannelTheme { /// Theme of the [ChannelHeader] widget diff --git a/lib/src/url_attachment.dart b/lib/src/url_attachment.dart index ad314455..1909fc33 100644 --- a/lib/src/url_attachment.dart +++ b/lib/src/url_attachment.dart @@ -51,17 +51,21 @@ class UrlAttachment extends StatelessWidget { ), child: Text( hostDisplayName, - style: TextStyle( - fontWeight: FontWeight.w700, - color: Color(0xFF006CFF), - ), + style: StreamChatTheme.of(context) + .textTheme + .bodyBold + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .accentBlue, + ), ), ), decoration: BoxDecoration( borderRadius: BorderRadius.only( 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(), maxLines: 1, overflow: TextOverflow.ellipsis, - style: TextStyle( - fontWeight: FontWeight.w700, - fontSize: 12.0, - ), + style: StreamChatTheme.of(context) + .textTheme + .body + .copyWith(fontWeight: FontWeight.w700), ), if (urlAttachment.text != null) Text( urlAttachment.text, - style: TextStyle( - fontWeight: FontWeight.w400, - fontSize: 12.0, - ), + style: StreamChatTheme.of(context) + .textTheme + .body + .copyWith(fontWeight: FontWeight.w400), ), ], ), diff --git a/lib/src/user_avatar.dart b/lib/src/user_avatar.dart index e698d773..688eff77 100644 --- a/lib/src/user_avatar.dart +++ b/lib/src/user_avatar.dart @@ -16,7 +16,7 @@ class UserAvatar extends StatelessWidget { this.borderRadius, this.onlineIndicatorAlignment = Alignment.topRight, this.selected = false, - this.selectionColor = const Color(0xFF006CFF), + this.selectionColor, this.selectionThickness = 4, }) : super(key: key); @@ -47,7 +47,7 @@ class UserAvatar extends StatelessWidget { constraints: constraints ?? streamChatTheme.ownMessageTheme.avatarTheme.constraints, decoration: BoxDecoration( - color: streamChatTheme.accentColor, + color: streamChatTheme.colorTheme.accentBlue, ), child: hasImage ? CachedNetworkImage( @@ -70,7 +70,8 @@ class UserAvatar extends StatelessWidget { child: Container( constraints: constraints ?? streamChatTheme.ownMessageTheme.avatarTheme.constraints, - color: selectionColor, + color: selectionColor ?? + StreamChatTheme.of(context).colorTheme.accentBlue, child: Padding( padding: EdgeInsets.all(selectionThickness), child: avatar, @@ -99,10 +100,10 @@ class UserAvatar extends StatelessWidget { ), child: Material( shape: CircleBorder(), - color: Color(0xff20E070), + color: streamChatTheme.colorTheme.accentGreen, ), ), - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, ), ), ), diff --git a/lib/src/user_item.dart b/lib/src/user_item.dart index 4c1af658..50a8b7a7 100644 --- a/lib/src/user_item.dart +++ b/lib/src/user_item.dart @@ -74,24 +74,30 @@ class UserItem extends StatelessWidget { ), trailing: selected ? CircleAvatar( + backgroundColor: + StreamChatTheme.of(context).colorTheme.accentBlue, child: StreamSvgIcon.check( size: 20, - color: Colors.white, + color: StreamChatTheme.of(context).colorTheme.white, ), radius: 10, ) : null, title: Text( user.name, - style: TextStyle(fontWeight: FontWeight.bold), + style: StreamChatTheme.of(context).textTheme.bodyBold, ), subtitle: showLastOnline ? _buildLastActive(context) : null, ); } Widget _buildLastActive(context) { - return user.online == true - ? Text('Online') - : Text('Last online ${Jiffy(user.lastActive).fromNow()}'); + return Text( + user.online == true + ? 'Online' + : 'Last online ${Jiffy(user.lastActive).fromNow()}', + style: StreamChatTheme.of(context).textTheme.footnote.copyWith( + color: StreamChatTheme.of(context).colorTheme.black.withOpacity(.5)), + ); } } diff --git a/lib/src/user_list_view.dart b/lib/src/user_list_view.dart index 59ba7f67..35692841 100644 --- a/lib/src/user_list_view.dart +++ b/lib/src/user_list_view.dart @@ -356,15 +356,19 @@ class _UserListViewState extends State headerItem: (header) { return Container( key: ValueKey('HEADER-$header'), - color: Colors.black.withOpacity(0.05), + color: + StreamChatTheme.of(context).colorTheme.black.withOpacity(0.05), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 6), child: Text( header, style: TextStyle( fontWeight: FontWeight.bold, - fontSize: 12, - color: Colors.black.withOpacity(0.3)), + fontSize: 14.5, + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.3)), ), ), ); @@ -449,7 +453,10 @@ class _UserListViewState extends State builder: (context, snapshot) { if (snapshot.hasError) { return Container( - color: Color(0xffd0021B).withAlpha(26), + color: StreamChatTheme.of(context) + .colorTheme + .accentRed + .withOpacity(.2), child: Padding( padding: const EdgeInsets.symmetric(vertical: 16.0), child: Center( @@ -472,8 +479,8 @@ class _UserListViewState extends State return Container( height: 1, color: Theme.of(context).brightness == Brightness.dark - ? Colors.white.withOpacity(0.1) - : Colors.black.withOpacity(0.1), + ? StreamChatTheme.of(context).colorTheme.white.withOpacity(0.1) + : StreamChatTheme.of(context).colorTheme.black.withOpacity(0.1), ); } diff --git a/lib/src/utils.dart b/lib/src/utils.dart index 681a28aa..32681d6e 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -25,7 +25,7 @@ Future showConfirmationDialog( String cancelText, }) { return showModalBottomSheet( - backgroundColor: Colors.white, + backgroundColor: StreamChatTheme.of(context).colorTheme.white, context: context, shape: RoundedRectangleBorder( borderRadius: BorderRadius.only( @@ -45,7 +45,7 @@ Future showConfirmationDialog( ), Text( title, - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16.0), + style: StreamChatTheme.of(context).textTheme.headlineBold, ), SizedBox( height: 7.0, @@ -55,7 +55,8 @@ Future showConfirmationDialog( height: 36.0, ), Container( - color: Color(0xffe6e6e6), + color: + StreamChatTheme.of(context).colorTheme.black.withOpacity(.08), height: 1.0, ), Row( @@ -65,7 +66,10 @@ Future showConfirmationDialog( child: Text( cancelText, style: TextStyle( - color: Colors.black.withOpacity(0.5), + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(0.5), fontWeight: FontWeight.w400), ), onPressed: () {