Merge branch 'feature/new-ui' of github.com:GetStream/stream-chat-flutter into feat/mention-screen

 Conflicts:
	lib/src/message_list_view.dart
This commit is contained in:
Sahil Kumar
2021-01-07 11:00:31 +05:30
87 changed files with 6038 additions and 3166 deletions
+259 -117
View File
@@ -1,8 +1,9 @@
import 'dart:async';
import 'dart:io';
import 'package:example/chat_info_screen.dart';
import 'package:example/choose_user_page.dart';
import 'package:example/new_chat_screen.dart';
import 'package:example/new_group_chat_screen.dart';
import 'package:example/group_info_screen.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
@@ -13,7 +14,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 +27,7 @@ void main() async {
logLevel: Level.INFO,
showLocalNotification:
(!kIsWeb && Platform.isAndroid) ? showLocalNotification : null,
persistenceEnabled: true,
persistenceEnabled: false,
);
if (userId != null) {
@@ -51,18 +51,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.system,
onGenerateRoute: AppRoutes.generateRoute,
initialRoute:
client.state.user == null ? Routes.CHOOSE_USER : Routes.HOME,
);
}
}
@@ -84,7 +86,9 @@ class _HomePageState extends State<HomePage> {
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 +104,9 @@ class _HomePageState extends State<HomePage> {
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 +119,7 @@ class _HomePageState extends State<HomePage> {
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 +128,14 @@ class _HomePageState extends State<HomePage> {
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 +153,116 @@ class _HomePageState extends State<HomePage> {
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,
),
),
),
),
),
],
],
),
),
),
),
@@ -467,6 +490,32 @@ class _ChannelListPageState extends State<ChannelListPage> {
limit: 20,
),
channelWidget: ChannelPage(),
onViewInfoTap: (channel) {
if (channel.memberCount == 2 &&
channel.isDistinct) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => StreamChannel(
channel: channel,
child: ChatInfoScreen(
user: channel.state.members.first.user,
),
),
),
);
} else {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => StreamChannel(
channel: channel,
child: GroupInfoScreen(),
),
),
);
}
},
),
),
),
@@ -489,7 +538,7 @@ class ChannelPageArgs {
});
}
class ChannelPage extends StatelessWidget {
class ChannelPage extends StatefulWidget {
final int initialScrollIndex;
final double initialAlignment;
final bool highlightInitialMessage;
@@ -501,12 +550,75 @@ class ChannelPage extends StatelessWidget {
this.highlightInitialMessage = false,
}) : super(key: key);
@override
_ChannelPageState createState() => _ChannelPageState();
}
class _ChannelPageState extends State<ChannelPage> {
Message _quotedMessage;
FocusNode _focusNode;
@override
void initState() {
super.initState();
_focusNode = FocusNode();
}
@override
void dispose() {
_focusNode.dispose();
super.dispose();
}
void _reply(Message message) {
setState(() => _quotedMessage = message);
_focusNode.requestFocus();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color.fromRGBO(252, 252, 252, 1),
backgroundColor: StreamChatTheme.of(context).colorTheme.whiteSnow,
appBar: ChannelHeader(
showTypingIndicator: false,
onImageTap: () async {
var channel = StreamChannel.of(context).channel;
if (channel.memberCount == 2 && channel.isDistinct) {
final currentUser = StreamChat.of(context).user;
final otherUser = channel.state.members.firstWhere(
(element) => element.user.id != currentUser.id,
orElse: () => null,
);
if (otherUser != null) {
final pop = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => StreamChannel(
child: ChatInfoScreen(
user: otherUser.user,
),
channel: channel,
),
),
);
if (pop == true) {
Navigator.pop(context);
}
}
} else {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => StreamChannel(
child: GroupInfoScreen(),
channel: channel,
),
),
);
}
},
),
body: Column(
children: <Widget>[
@@ -514,14 +626,35 @@ class ChannelPage extends StatelessWidget {
child: Stack(
children: <Widget>[
MessageListView(
initialScrollIndex: initialScrollIndex,
initialAlignment: initialAlignment,
highlightInitialMessage: highlightInitialMessage,
initialScrollIndex: widget.initialScrollIndex,
initialAlignment: widget.initialAlignment,
highlightInitialMessage: widget.highlightInitialMessage,
onMessageSwiped: _reply,
onReplyTap: _reply,
threadBuilder: (_, parentMessage) {
return ThreadPage(
parent: parentMessage,
);
},
onShowMessage: (m, c) async {
final client = StreamChat.of(context).client;
final message = m;
final channel = client.channel(
c.type,
id: c.id,
);
if (channel.state == null) {
await channel.watch();
}
Navigator.pushReplacementNamed(
context,
Routes.CHANNEL_PAGE,
arguments: ChannelPageArgs(
channel: channel,
initialMessage: message,
),
);
},
),
Positioned(
bottom: 0,
@@ -529,7 +662,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(
@@ -542,7 +678,13 @@ class ChannelPage extends StatelessWidget {
],
),
),
MessageInput(),
MessageInput(
focusNode: _focusNode,
quotedMessage: _quotedMessage,
onQuotedMessageCleared: () {
setState(() => _quotedMessage = null);
},
),
],
),
);
@@ -564,7 +706,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,
),