diff --git a/example/lib/advanced_options_page.dart b/example/lib/advanced_options_page.dart index 9160a5d9..7555f286 100644 --- a/example/lib/advanced_options_page.dart +++ b/example/lib/advanced_options_page.dart @@ -60,15 +60,11 @@ class _AdvancedOptionsPageState extends State { body: Builder( builder: (context) { return Padding( - padding: const EdgeInsets.fromLTRB( - 16, - 16, - 16, - 0, - ), + padding: const EdgeInsets.fromLTRB(16, 16, 16, 0), child: Form( key: _formKey, child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, children: [ TextFormField( controller: _apiKeyController, @@ -93,16 +89,13 @@ class _AdvancedOptionsPageState extends State { color: StreamChatTheme.of(context).colorTheme.black, ), decoration: InputDecoration( - errorStyle: TextStyle(fontSize: 0), + errorStyle: TextStyle(height: 0, fontSize: 0), labelStyle: TextStyle( fontSize: 14, fontWeight: FontWeight.bold, color: _apiKeyError != null ? StreamChatTheme.of(context).colorTheme.accentRed - : StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(.5), + : StreamChatTheme.of(context).colorTheme.grey, ), border: UnderlineInputBorder( borderRadius: BorderRadius.circular(8), @@ -112,264 +105,231 @@ class _AdvancedOptionsPageState extends State { StreamChatTheme.of(context).colorTheme.whiteSmoke, filled: true, labelText: - 'Chat API Key ${_apiKeyError != null ? ':$_apiKeyError' : ''}', + 'Chat API Key ${_apiKeyError != null ? ': $_apiKeyError' : ''}', ), textInputAction: TextInputAction.next, ), - Padding( - padding: const EdgeInsets.only(top: 8.0), - child: TextFormField( - controller: _userIdController, - onChanged: (_) { - if (_userIdError != null) { - setState(() { - _userIdError = null; - }); - } - }, - validator: (value) { - if (value.isEmpty) { - setState(() { - _userIdError = 'Please enter the User ID'; - }); - return _userIdError; - } - return null; - }, - style: TextStyle( + SizedBox(height: 8), + TextFormField( + controller: _userIdController, + onChanged: (_) { + if (_userIdError != null) { + setState(() { + _userIdError = null; + }); + } + }, + validator: (value) { + if (value.isEmpty) { + setState(() { + _userIdError = 'Please enter the User ID'; + }); + return _userIdError; + } + return null; + }, + style: TextStyle( + fontSize: 14, + color: StreamChatTheme.of(context).colorTheme.black, + ), + textInputAction: TextInputAction.next, + decoration: InputDecoration( + errorStyle: TextStyle(height: 0, fontSize: 0), + labelStyle: TextStyle( + fontWeight: FontWeight.bold, fontSize: 14, - color: StreamChatTheme.of(context).colorTheme.black, + color: _userIdError != null + ? StreamChatTheme.of(context).colorTheme.accentRed + : StreamChatTheme.of(context).colorTheme.grey, ), - textInputAction: TextInputAction.next, - decoration: InputDecoration( - errorStyle: TextStyle(fontSize: 0), - labelStyle: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14, - color: _userIdError != null - ? StreamChatTheme.of(context).colorTheme.accentRed - : StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(.5), - ), - border: UnderlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: BorderSide.none, - ), - fillColor: - StreamChatTheme.of(context).colorTheme.whiteSmoke, - filled: true, - labelText: - 'User ID ${_userIdError != null ? ':$_userIdError' : ''}', + border: UnderlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide.none, ), + fillColor: + StreamChatTheme.of(context).colorTheme.whiteSmoke, + filled: true, + labelText: + 'User ID ${_userIdError != null ? ': $_userIdError' : ''}', ), ), - Padding( - padding: const EdgeInsets.only(top: 8.0), - child: TextFormField( - onChanged: (_) { - if (_userTokenError != null) { - setState(() { - _userTokenError = null; - }); - } - }, - controller: _userTokenController, - validator: (value) { - if (value.isEmpty) { - setState(() { - _userTokenError = 'Please enter the user token'; - }); - return _userTokenError; - } - return null; - }, - style: TextStyle( + SizedBox(height: 8), + TextFormField( + onChanged: (_) { + if (_userTokenError != null) { + setState(() { + _userTokenError = null; + }); + } + }, + controller: _userTokenController, + validator: (value) { + if (value.isEmpty) { + setState(() { + _userTokenError = 'Please enter the user token'; + }); + return _userTokenError; + } + return null; + }, + style: TextStyle( + fontSize: 14, + color: StreamChatTheme.of(context).colorTheme.black, + ), + textInputAction: TextInputAction.next, + decoration: InputDecoration( + errorStyle: TextStyle(height: 0, fontSize: 0), + labelStyle: TextStyle( + fontWeight: FontWeight.bold, fontSize: 14, - color: StreamChatTheme.of(context).colorTheme.black, + color: _userTokenError != null + ? StreamChatTheme.of(context).colorTheme.accentRed + : StreamChatTheme.of(context).colorTheme.grey, ), - textInputAction: TextInputAction.next, - decoration: InputDecoration( - errorStyle: TextStyle(fontSize: 0), - labelStyle: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14, - color: _userTokenError != null - ? StreamChatTheme.of(context).colorTheme.accentRed - : StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(.5), - ), - border: UnderlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: BorderSide.none, - ), - fillColor: - StreamChatTheme.of(context).colorTheme.whiteSmoke, - filled: true, - labelText: - 'User Token ${_userTokenError != null ? ':$_userTokenError' : ''}', + border: UnderlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide.none, ), + fillColor: + StreamChatTheme.of(context).colorTheme.whiteSmoke, + filled: true, + labelText: + 'User Token ${_userTokenError != null ? ': $_userTokenError' : ''}', ), ), - Padding( - padding: const EdgeInsets.only(top: 8.0), - child: TextFormField( - controller: _usernameController, - textInputAction: TextInputAction.done, - decoration: InputDecoration( - labelStyle: TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(.5), - ), - border: UnderlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: BorderSide.none, - ), - fillColor: - StreamChatTheme.of(context).colorTheme.whiteSmoke, - filled: true, - labelText: 'Username (optional)', + SizedBox(height: 8), + TextFormField( + controller: _usernameController, + textInputAction: TextInputAction.done, + decoration: InputDecoration( + labelStyle: TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, + color: StreamChatTheme.of(context).colorTheme.grey, ), + border: UnderlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide.none, + ), + fillColor: + StreamChatTheme.of(context).colorTheme.whiteSmoke, + filled: true, + labelText: 'Username (optional)', ), ), - Expanded( - child: Align( - alignment: Alignment.bottomCenter, - child: FlatButton( - color: - StreamChatTheme.of(context).colorTheme.accentBlue, - minWidth: double.infinity, - height: 48, - child: Text( - 'Login', - style: TextStyle( - color: StreamChatTheme.of(context).colorTheme.white, - fontSize: 16, - ), - ), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(26), - ), - onPressed: () async { - if (loading) { - return; - } - if (_formKey.currentState.validate()) { - final apiKey = _apiKeyController.text; - final userId = _userIdController.text; - final userToken = _userTokenController.text; - final username = _usernameController.text; + Spacer(), + RaisedButton( + elevation: 0, + child: Text('Login', style: TextStyle(fontSize: 16)), + onPressed: () async { + if (loading) { + return; + } + if (_formKey.currentState.validate()) { + final apiKey = _apiKeyController.text; + final userId = _userIdController.text; + final userToken = _userTokenController.text; + final username = _usernameController.text; - loading = true; - showDialog( - barrierDismissible: false, - context: context, - barrierColor: StreamChatTheme.of(context) - .colorTheme - .overlay, - builder: (context) => Center( - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(16), - color: StreamChatTheme.of(context) - .colorTheme - .white, - ), - height: 100, - width: 100, - child: Center( - child: CircularProgressIndicator(), - ), - ), + loading = true; + showDialog( + barrierDismissible: false, + context: context, + barrierColor: + StreamChatTheme.of(context).colorTheme.overlay, + builder: (context) => Center( + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(16), + color: StreamChatTheme.of(context) + .colorTheme + .white, ), - ); + height: 100, + width: 100, + child: Center( + child: CircularProgressIndicator(), + ), + ), + ), + ); - final client = Client( - apiKey, - logLevel: Level.INFO, - showLocalNotification: - (!kIsWeb && Platform.isAndroid) - ? showLocalNotification - : null, - persistenceEnabled: true, - ); + final client = Client( + apiKey, + logLevel: Level.INFO, + showLocalNotification: (!kIsWeb && Platform.isAndroid) + ? showLocalNotification + : null, + persistenceEnabled: true, + ); - try { - await client.setUser( - User(id: userId, extraData: { - 'name': username, - }), - userToken, - ); + try { + await client.setUser( + User(id: userId, extraData: { + 'name': username, + }), + userToken, + ); - if (!kIsWeb) { - initNotifications(client); - } + if (!kIsWeb) { + initNotifications(client); + } - final secureStorage = FlutterSecureStorage(); - secureStorage.write( - key: kStreamApiKey, - value: apiKey, - ); - secureStorage.write( - key: kStreamUserId, - value: userId, - ); - secureStorage.write( - key: kStreamToken, - value: userToken, - ); - } catch (e) { - var errorText = 'Error connecting, retry'; - if (e is Map) { - errorText = e['message'] ?? errorText; - } - Navigator.pop(context); - setState(() { - _apiKeyError = errorText; - }); - loading = false; - await client.disconnect(); - return; - } + final secureStorage = FlutterSecureStorage(); + secureStorage.write( + key: kStreamApiKey, + value: apiKey, + ); + secureStorage.write( + key: kStreamUserId, + value: userId, + ); + secureStorage.write( + key: kStreamToken, + value: userToken, + ); + } catch (e) { + var errorText = 'Error connecting, retry'; + if (e is Map) { + errorText = e['message'] ?? errorText; + } + Navigator.pop(context); + setState(() { + _apiKeyError = errorText; + }); + loading = false; + await client.disconnect(); + return; + } - if (!kIsWeb) { - initNotifications(client); - } + if (!kIsWeb) { + initNotifications(client); + } - Navigator.pop(context); - Navigator.pop(context); - await Navigator.pushReplacement( - context, - MaterialPageRoute( - builder: (context) { - return MaterialApp( - theme: ThemeData.light(), - darkTheme: ThemeData.dark(), - themeMode: ThemeMode.system, - builder: (context, widget) { - return StreamChat( - child: widget, - client: client, - ); - }, - home: ChannelListPage(), + Navigator.pop(context); + Navigator.pop(context); + await Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) { + return MaterialApp( + theme: ThemeData.light(), + darkTheme: ThemeData.dark(), + themeMode: ThemeMode.system, + builder: (context, widget) { + return StreamChat( + child: widget, + client: client, ); }, - ), - ); - loading = false; - } - }, - ), - ), + home: ChannelListPage(), + ); + }, + ), + ); + loading = false; + } + }, ), StreamVersion(), ], diff --git a/example/lib/choose_user_page.dart b/example/lib/choose_user_page.dart index ede5f6df..6da88a29 100644 --- a/example/lib/choose_user_page.dart +++ b/example/lib/choose_user_page.dart @@ -72,6 +72,7 @@ class ChooseUserPage extends StatelessWidget { child: SvgPicture.asset( 'assets/logo.svg', height: 40, + color: StreamChatTheme.of(context).colorTheme.accentBlue, ), ), ), @@ -92,9 +93,8 @@ class ChooseUserPage extends StatelessWidget { child: ListView.separated( separatorBuilder: (context, i) { return Container( - width: double.infinity, - color: Colors.black12, height: 1, + color: StreamChatTheme.of(context).colorTheme.greyWhisper, ); }, itemCount: users.length + 1, @@ -180,10 +180,10 @@ class ChooseUserPage extends StatelessWidget { .grey, ), ), - trailing: SvgPicture.asset( - 'assets/icon_arrow_right.svg', - height: 24, - width: 24, + trailing: StreamSvgIcon.arrow_right( + color: StreamChatTheme.of(context) + .colorTheme + .accentBlue, ), ); }), diff --git a/example/lib/stream_version.dart b/example/lib/stream_version.dart index a3d52ab6..b3f926be 100644 --- a/example/lib/stream_version.dart +++ b/example/lib/stream_version.dart @@ -28,9 +28,8 @@ class StreamVersion extends StatelessWidget { return Text( 'Stream SDK v ${streamChatDep}', style: TextStyle( - fontSize: 14.5, - color: - StreamChatTheme.of(context).colorTheme.black.withOpacity(.13), + fontSize: 14, + color: StreamChatTheme.of(context).colorTheme.greyGainsboro, ), ); }, diff --git a/lib/src/stream_chat.dart b/lib/src/stream_chat.dart index 4b012ef0..b5883fdb 100644 --- a/lib/src/stream_chat.dart +++ b/lib/src/stream_chat.dart @@ -78,6 +78,7 @@ class StreamChatState extends State with WidgetsBindingObserver { primaryIconTheme: streamTheme.primaryIconTheme, accentColor: streamTheme.colorTheme.accentBlue, scaffoldBackgroundColor: streamTheme.colorTheme.white, + buttonTheme: streamTheme.buttonTheme, ), child: widget.child, ); diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index 3fac4173..8640467c 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -45,6 +45,9 @@ class StreamChatThemeData { /// The text themes used in the widgets final TextTheme textTheme; + /// The button themes used in the widgets + final ButtonThemeData buttonTheme; + /// The text themes used in the widgets final ColorTheme colorTheme; @@ -75,6 +78,7 @@ class StreamChatThemeData { /// Create a theme from scratch const StreamChatThemeData({ this.textTheme, + this.buttonTheme, this.colorTheme, this.channelPreviewTheme, this.channelTheme, @@ -106,6 +110,7 @@ class StreamChatThemeData { /// Creates a copy of [StreamChatThemeData] with specified attributes overridden. StreamChatThemeData copyWith({ TextTheme textTheme, + ButtonThemeData buttonTheme, ColorTheme colorTheme, ChannelPreviewTheme channelPreviewTheme, ChannelTheme channelTheme, @@ -118,6 +123,7 @@ class StreamChatThemeData { }) => StreamChatThemeData( textTheme: textTheme ?? this.textTheme, + buttonTheme: buttonTheme ?? this.buttonTheme, colorTheme: colorTheme ?? this.colorTheme, primaryIconTheme: primaryIconTheme ?? this.primaryIconTheme, defaultChannelImage: defaultChannelImage ?? this.defaultChannelImage, @@ -133,6 +139,7 @@ class StreamChatThemeData { if (other == null) return this; return copyWith( textTheme: textTheme?.merge(other.textTheme) ?? other.textTheme, + buttonTheme: other.buttonTheme, colorTheme: colorTheme?.merge(other.colorTheme) ?? other.colorTheme, primaryIconTheme: other.primaryIconTheme, defaultChannelImage: other.defaultChannelImage, @@ -159,6 +166,17 @@ class StreamChatThemeData { return StreamChatThemeData( textTheme: textTheme, colorTheme: colorTheme, + buttonTheme: ButtonThemeData( + height: 48.0, + buttonColor: isDark ? Color(0xffffffff) : Color(0xff006aff), + textTheme: ButtonTextTheme.accent, + colorScheme: theme.colorScheme.copyWith( + secondary: isDark ? Color(0xff005eff) : Color(0xffffffff), + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(26), + ), + ), primaryIconTheme: IconThemeData(color: colorTheme.black.withOpacity(.5)), defaultChannelImage: (context, channel) => SizedBox(), defaultUserImage: (context, user) => Center( @@ -475,7 +493,7 @@ class ColorTheme { this.white = const Color(0xffffffff), this.blueAlice = const Color(0xffe9f2ff), this.accentBlue = const Color(0xff005FFF), - this.accentRed = const Color(0xffFF3742), + this.accentRed = const Color(0xffFF3842), this.accentGreen = const Color(0xff20E070), this.highlight = const Color(0xfffbf4dd), this.overlay = const Color.fromRGBO(0, 0, 0, 0.2),