Merge pull request #157 from GetStream/add-bottom-nav
Add bottomNavigationBar
This commit is contained in:
@@ -155,11 +155,9 @@ class ChooseUserPage extends StatelessWidget {
|
|||||||
if (!kIsWeb) {
|
if (!kIsWeb) {
|
||||||
initNotifications(client);
|
initNotifications(client);
|
||||||
}
|
}
|
||||||
Navigator.pushNamedAndRemoveUntil(
|
Navigator.pushReplacementNamed(
|
||||||
context,
|
context,
|
||||||
Routes.CHANNEL_LIST,
|
Routes.HOME,
|
||||||
ModalRoute.withName(Routes.CHANNEL_LIST),
|
|
||||||
arguments: client,
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
leading: UserAvatar(
|
leading: UserAvatar(
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ class _GroupChatDetailsScreenState extends State<GroupChatDetailsScreen> {
|
|||||||
Navigator.pushNamedAndRemoveUntil(
|
Navigator.pushNamedAndRemoveUntil(
|
||||||
context,
|
context,
|
||||||
Routes.CHANNEL_PAGE,
|
Routes.CHANNEL_PAGE,
|
||||||
ModalRoute.withName(Routes.CHANNEL_LIST),
|
ModalRoute.withName(Routes.HOME),
|
||||||
arguments: channel,
|
arguments: channel,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
+162
-92
@@ -60,51 +60,53 @@ class MyApp extends StatelessWidget {
|
|||||||
//TODO change to system once dark theme is implemented
|
//TODO change to system once dark theme is implemented
|
||||||
themeMode: ThemeMode.light,
|
themeMode: ThemeMode.light,
|
||||||
onGenerateRoute: AppRoutes.generateRoute,
|
onGenerateRoute: AppRoutes.generateRoute,
|
||||||
initialRoute: client.state.user == null
|
initialRoute:
|
||||||
? Routes.CHOOSE_USER
|
client.state.user == null ? Routes.CHOOSE_USER : Routes.HOME,
|
||||||
: Routes.CHANNEL_LIST,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ChannelListPage extends StatefulWidget {
|
class HomePage extends StatefulWidget {
|
||||||
@override
|
@override
|
||||||
_ChannelListPageState createState() => _ChannelListPageState();
|
_HomePageState createState() => _HomePageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ChannelListPageState extends State<ChannelListPage> {
|
class _HomePageState extends State<HomePage> {
|
||||||
TextEditingController _controller;
|
int _currentIndex = 0;
|
||||||
|
|
||||||
String _channelQuery = '';
|
bool _isSelected(int index) => _currentIndex == index;
|
||||||
|
|
||||||
bool _isSearchActive = false;
|
List<BottomNavigationBarItem> get _navBarItems {
|
||||||
|
return <BottomNavigationBarItem>[
|
||||||
Timer _debounce;
|
BottomNavigationBarItem(
|
||||||
|
icon: Stack(
|
||||||
void _channelQueryListener() {
|
overflow: Overflow.visible,
|
||||||
if (_debounce?.isActive ?? false) _debounce.cancel();
|
children: [
|
||||||
_debounce = Timer(const Duration(milliseconds: 350), () {
|
StreamSvgIcon.message(
|
||||||
if (mounted) {
|
color: _isSelected(0) ? Colors.black : Colors.grey,
|
||||||
setState(() {
|
),
|
||||||
_channelQuery = _controller.text;
|
Positioned(
|
||||||
_isSearchActive = _channelQuery.isNotEmpty;
|
top: -3,
|
||||||
});
|
right: -16,
|
||||||
}
|
child: UnreadIndicator(),
|
||||||
});
|
),
|
||||||
}
|
],
|
||||||
|
),
|
||||||
@override
|
label: 'Chats',
|
||||||
void initState() {
|
),
|
||||||
super.initState();
|
BottomNavigationBarItem(
|
||||||
_controller = TextEditingController()..addListener(_channelQueryListener);
|
icon: Stack(
|
||||||
}
|
overflow: Overflow.visible,
|
||||||
|
children: [
|
||||||
@override
|
StreamSvgIcon.mentions(
|
||||||
void dispose() {
|
color: _isSelected(1) ? Colors.black : Colors.grey,
|
||||||
_controller?.removeListener(_channelQueryListener);
|
),
|
||||||
_controller?.dispose();
|
],
|
||||||
super.dispose();
|
),
|
||||||
|
label: 'Mentions',
|
||||||
|
),
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -118,63 +120,22 @@ class _ChannelListPageState extends State<ChannelListPage> {
|
|||||||
),
|
),
|
||||||
drawer: _buildDrawer(context, user),
|
drawer: _buildDrawer(context, user),
|
||||||
drawerEdgeDragWidth: 50,
|
drawerEdgeDragWidth: 50,
|
||||||
body: ChannelsBloc(
|
bottomNavigationBar: BottomNavigationBar(
|
||||||
child: MessageSearchBloc(
|
currentIndex: _currentIndex,
|
||||||
child: Column(
|
items: _navBarItems,
|
||||||
children: [
|
type: BottomNavigationBarType.fixed,
|
||||||
SearchTextField(
|
selectedItemColor: Colors.black,
|
||||||
controller: _controller,
|
unselectedItemColor: Colors.grey,
|
||||||
),
|
onTap: (index) {
|
||||||
Expanded(
|
setState(() => _currentIndex = index);
|
||||||
child: AnimatedSwitcher(
|
},
|
||||||
duration: const Duration(milliseconds: 350),
|
),
|
||||||
child: GestureDetector(
|
body: IndexedStack(
|
||||||
behavior: HitTestBehavior.opaque,
|
index: _currentIndex,
|
||||||
onPanDown: (_) => FocusScope.of(context).unfocus(),
|
children: [
|
||||||
child: _isSearchActive
|
ChannelListPage(),
|
||||||
? MessageSearchListView(
|
UserMentionPage(),
|
||||||
messageQuery: _channelQuery,
|
],
|
||||||
filters: {
|
|
||||||
'members': {
|
|
||||||
r'$in': [user.id]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
sortOptions: [
|
|
||||||
SortOption(
|
|
||||||
'created_at',
|
|
||||||
direction: SortOption.ASC,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
paginationParams: PaginationParams(limit: 20),
|
|
||||||
onItemTap: (message) {},
|
|
||||||
)
|
|
||||||
: ChannelListView(
|
|
||||||
onStartChatPressed: () {
|
|
||||||
Navigator.pushNamed(context, Routes.NEW_CHAT);
|
|
||||||
},
|
|
||||||
swipeToAction: true,
|
|
||||||
filter: {
|
|
||||||
'members': {
|
|
||||||
r'$in': [user.id],
|
|
||||||
},
|
|
||||||
'draft': {
|
|
||||||
r'$ne': true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
'presence': true,
|
|
||||||
},
|
|
||||||
pagination: PaginationParams(
|
|
||||||
limit: 20,
|
|
||||||
),
|
|
||||||
channelWidget: ChannelPage(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -282,6 +243,115 @@ class _ChannelListPageState extends State<ChannelListPage> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class UserMentionPage extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Center(
|
||||||
|
child: Text('On Pause Right Now!'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ChannelListPage extends StatefulWidget {
|
||||||
|
@override
|
||||||
|
_ChannelListPageState createState() => _ChannelListPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ChannelListPageState extends State<ChannelListPage> {
|
||||||
|
TextEditingController _controller;
|
||||||
|
|
||||||
|
String _channelQuery = '';
|
||||||
|
|
||||||
|
bool _isSearchActive = false;
|
||||||
|
|
||||||
|
Timer _debounce;
|
||||||
|
|
||||||
|
void _channelQueryListener() {
|
||||||
|
if (_debounce?.isActive ?? false) _debounce.cancel();
|
||||||
|
_debounce = Timer(const Duration(milliseconds: 350), () {
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_channelQuery = _controller.text;
|
||||||
|
_isSearchActive = _channelQuery.isNotEmpty;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_controller = TextEditingController()..addListener(_channelQueryListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_controller?.removeListener(_channelQueryListener);
|
||||||
|
_controller?.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final user = StreamChat.of(context).user;
|
||||||
|
return ChannelsBloc(
|
||||||
|
child: MessageSearchBloc(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
SearchTextField(
|
||||||
|
controller: _controller,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: AnimatedSwitcher(
|
||||||
|
duration: const Duration(milliseconds: 350),
|
||||||
|
child: GestureDetector(
|
||||||
|
behavior: HitTestBehavior.opaque,
|
||||||
|
onPanDown: (_) => FocusScope.of(context).unfocus(),
|
||||||
|
child: _isSearchActive
|
||||||
|
? MessageSearchListView(
|
||||||
|
messageQuery: _channelQuery,
|
||||||
|
filters: {
|
||||||
|
'members': {
|
||||||
|
r'$in': [user.id]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
sortOptions: [
|
||||||
|
SortOption(
|
||||||
|
'created_at',
|
||||||
|
direction: SortOption.ASC,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
paginationParams: PaginationParams(limit: 20),
|
||||||
|
onItemTap: (message) {},
|
||||||
|
)
|
||||||
|
: ChannelListView(
|
||||||
|
onStartChatPressed: () {
|
||||||
|
Navigator.pushNamed(context, Routes.NEW_CHAT);
|
||||||
|
},
|
||||||
|
swipeToAction: true,
|
||||||
|
filter: {
|
||||||
|
'members': {
|
||||||
|
r'$in': [user.id],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
'presence': true,
|
||||||
|
},
|
||||||
|
pagination: PaginationParams(
|
||||||
|
limit: 20,
|
||||||
|
),
|
||||||
|
channelWidget: ChannelPage(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class ChannelQuerySearchResultPage extends StatelessWidget {
|
class ChannelQuerySearchResultPage extends StatelessWidget {
|
||||||
final Stream<List<Message>> searchResultStream;
|
final Stream<List<Message>> searchResultStream;
|
||||||
|
|
||||||
|
|||||||
@@ -338,7 +338,7 @@ class _NewChatScreenState extends State<NewChatScreen> {
|
|||||||
Navigator.pushNamedAndRemoveUntil(
|
Navigator.pushNamedAndRemoveUntil(
|
||||||
context,
|
context,
|
||||||
Routes.CHANNEL_PAGE,
|
Routes.CHANNEL_PAGE,
|
||||||
ModalRoute.withName(Routes.CHANNEL_LIST),
|
ModalRoute.withName(Routes.HOME),
|
||||||
arguments: channel,
|
arguments: channel,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,11 +13,11 @@ class AppRoutes {
|
|||||||
static Route<dynamic> generateRoute(RouteSettings settings) {
|
static Route<dynamic> generateRoute(RouteSettings settings) {
|
||||||
final args = settings.arguments;
|
final args = settings.arguments;
|
||||||
switch (settings.name) {
|
switch (settings.name) {
|
||||||
case Routes.CHANNEL_LIST:
|
case Routes.HOME:
|
||||||
return MaterialPageRoute(
|
return MaterialPageRoute(
|
||||||
settings: const RouteSettings(name: Routes.CHANNEL_LIST),
|
settings: const RouteSettings(name: Routes.HOME),
|
||||||
builder: (_) {
|
builder: (_) {
|
||||||
return ChannelListPage();
|
return HomePage();
|
||||||
});
|
});
|
||||||
case Routes.CHOOSE_USER:
|
case Routes.CHOOSE_USER:
|
||||||
return MaterialPageRoute(
|
return MaterialPageRoute(
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/// Define all the route names here
|
/// Define all the route names here
|
||||||
class Routes {
|
class Routes {
|
||||||
static const String CHANNEL_LIST = '/channel_list';
|
static const String HOME = '/home';
|
||||||
static const String CHOOSE_USER = '/choose_user';
|
static const String CHOOSE_USER = '/choose_user';
|
||||||
static const String ADVANCED_OPTIONS = '/advance_options';
|
static const String ADVANCED_OPTIONS = '/advance_options';
|
||||||
static const String CHANNEL_PAGE = '/channel_page';
|
static const String CHANNEL_PAGE = '/channel_page';
|
||||||
|
|||||||
@@ -41,3 +41,4 @@ export 'src/video_attachment.dart';
|
|||||||
export 'src/message_search_bloc.dart';
|
export 'src/message_search_bloc.dart';
|
||||||
export 'src/message_search_item.dart';
|
export 'src/message_search_item.dart';
|
||||||
export 'src/message_search_list_view.dart';
|
export 'src/message_search_list_view.dart';
|
||||||
|
export 'src/unread_indicator.dart';
|
||||||
|
|||||||
Reference in New Issue
Block a user