diff --git a/lib/src/ui/bottom_bar/bottom_bar.dart b/lib/src/ui/bottom_bar/bottom_bar.dart index 3dcf18d..55aaf7e 100644 --- a/lib/src/ui/bottom_bar/bottom_bar.dart +++ b/lib/src/ui/bottom_bar/bottom_bar.dart @@ -18,8 +18,8 @@ class BottomBar extends StatelessWidget { borderRadius: BorderRadius.only( topLeft: Radius.circular(40.0), topRight: Radius.circular(40.0)), child: Container( - padding: EdgeInsets.only( - top: 20.0, left: 20.0, right: 20.0, bottom: 30.0 + bottomPadding), + padding: + EdgeInsets.only(top: 20.0, left: 20.0, right: 20.0, bottom: 30.0), child: (conversationId == "") ? ConversationInactiveView() : ConversationActiveView(conversationId: conversationId), diff --git a/lib/src/ui/home/home.dart b/lib/src/ui/home/home.dart index b7c5a33..4b520af 100644 --- a/lib/src/ui/home/home.dart +++ b/lib/src/ui/home/home.dart @@ -1,39 +1,45 @@ import "package:flutter/material.dart"; +import 'dart:ui' as ui; import "./widgets/top_bar.dart"; -import "./widgets/conversation_list.dart"; -import "./widgets/contact_list.dart"; +import "./widgets/conversation_view.dart"; +import "./widgets/contact_view.dart"; import "../bottom_bar/bottom_bar.dart"; import "../../services/heartbeat_manager.dart"; import "../../services/conversation_manager.dart"; import "../../blocs/message_bloc.dart"; -import "../../blocs/heartbeat_bloc.dart"; class Home extends StatefulWidget { @override _HomeState createState() => _HomeState(); } -class _HomeState extends State { - final List titleList = ["Conversations", "Contacts", "Settings"]; - +class _HomeState extends State with SingleTickerProviderStateMixin { final GlobalKey _scaffoldKey = new GlobalKey(); - final PageController controller = PageController(); final heartbeatSendManager = HeartbeatSendManager(); final conversationManager = ConversationManager(); - int _pageNumber = 0; + // Bottom Bar navigation + final List titleList = ["Contacts", "Conversations", "Settings"]; + int _tabNumber = 1; + List itemsList = [ + Icons.contacts, + Icons.chat, + Icons.settings, + ]; + TabController controller; - PersistentBottomSheetController bottomBarController; + // Current conversaton + String currentConversationId = ""; @override initState() { super.initState(); - controller.addListener(_updatePageNumber); + controller = TabController(vsync: this, length: 3); + controller.index = 1; // Set default page to conversation page messageBloc.bus.listen( (Map data) async => await _processMessage(data)); - _setupBottomState(); } @override @@ -42,53 +48,75 @@ class _HomeState extends State { super.dispose(); } - _updatePageNumber() { - setState(() { - _pageNumber = controller.page.round(); - }); - } - _processMessage(Map data) async { if (data["state"] == "disconnect") { // Disconnect and change state await conversationManager.exit(); - bottomBarController.close(); - bottomBarController = _scaffoldKey.currentState.showBottomSheet( - (BuildContext context) => BottomBar(conversationId: "")); + setState(() { + currentConversationId = ""; + }); } else if (data["state"] == "connect") { // Connect and change state await conversationManager.join(data["conversationId"]); - bottomBarController.close(); - bottomBarController = _scaffoldKey.currentState.showBottomSheet( - (BuildContext context) => - BottomBar(conversationId: data["conversationId"])); + setState(() { + currentConversationId = data["conversationId"]; + }); } else { // show default await conversationManager.exit(); - bottomBarController.close(); - bottomBarController = _scaffoldKey.currentState.showBottomSheet( - (BuildContext context) => BottomBar(conversationId: "")); + setState(() { + currentConversationId = ""; + }); } } - _setupBottomState() { - conversationManager.get().then((conversationId) { - bottomBarController = _scaffoldKey.currentState.showBottomSheet( - (BuildContext context) => BottomBar(conversationId: conversationId)); - }); - } - @override Widget build(BuildContext context) { return Scaffold( key: _scaffoldKey, body: Column(children: [ - TopBar(title: titleList[_pageNumber], pageNumber: _pageNumber), + TopBar(title: titleList[_tabNumber]), Expanded( - child: PageView(controller: controller, children: [ - ConversationList(), - ContactList(), - ])), + child: TabBarView( + physics: NeverScrollableScrollPhysics(), + controller: controller, + children: [ + ContactView(), + ConversationView(), + Container(), + ])), + ]), + bottomNavigationBar: + Column(mainAxisSize: MainAxisSize.min, children: [ + BottomBar(conversationId: currentConversationId), + BottomNavigationBar( + onTap: (int index) { + setState(() { + _tabNumber = index; + controller.index = _tabNumber; + }); + }, + items: itemsList.map((data) { + return BottomNavigationBarItem( + icon: itemsList[_tabNumber] == data + ? ShaderMask( + blendMode: BlendMode.srcIn, + shaderCallback: (Rect bounds) { + return ui.Gradient.linear( + Offset(4.0, 24.0), + Offset(24.0, 4.0), + [ + Theme.of(context).primaryColor, + Theme.of(context).primaryColorDark, + ], + ); + }, + child: Icon(data), + ) + : Icon(data, color: Colors.grey), + title: Container(), + ); + }).toList()) ]), ); } diff --git a/lib/src/ui/home/widgets/contact_list.dart b/lib/src/ui/home/widgets/contact_view.dart similarity index 88% rename from lib/src/ui/home/widgets/contact_list.dart rename to lib/src/ui/home/widgets/contact_view.dart index 9161465..fd585b6 100644 --- a/lib/src/ui/home/widgets/contact_list.dart +++ b/lib/src/ui/home/widgets/contact_view.dart @@ -5,14 +5,14 @@ import "../../../blocs/contact_bloc.dart"; import "contact_item.dart"; -class ContactList extends StatefulWidget { +class ContactView extends StatefulWidget { @override State createState() { - return _ContactListState(); + return _ContactViewState(); } } -class _ContactListState extends State { +class _ContactViewState extends State { @override void initState() { super.initState(); diff --git a/lib/src/ui/home/widgets/conversation_item.dart b/lib/src/ui/home/widgets/conversation_item.dart index a76631c..6d0e39a 100644 --- a/lib/src/ui/home/widgets/conversation_item.dart +++ b/lib/src/ui/home/widgets/conversation_item.dart @@ -57,12 +57,12 @@ class _ConversationItemState extends State { Text(conversation.title, style: Theme.of(context).textTheme.title), Spacer(), - Text("1m ago", + Text("12:25 PM", style: Theme.of(context) .primaryTextTheme .body1 .copyWith( - fontWeight: FontWeight.w700, + fontWeight: FontWeight.w500, color: Theme.of(context).primaryColorDark)), ]), Padding( diff --git a/lib/src/ui/home/widgets/conversation_list.dart b/lib/src/ui/home/widgets/conversation_list.dart deleted file mode 100644 index 5e7e058..0000000 --- a/lib/src/ui/home/widgets/conversation_list.dart +++ /dev/null @@ -1,47 +0,0 @@ -import "package:flutter/material.dart"; - -import "../../../models/conversation_model.dart"; -import "../../../blocs/conversation_bloc.dart"; - -import "conversation_item.dart"; - -class ConversationList extends StatefulWidget { - @override - State createState() { - return _ConversationListState(); - } -} - -class _ConversationListState extends State { - @override - initState() { - super.initState(); - conversationsBloc.fetchConversations(); - } - - @override - Widget build(BuildContext context) { - return Padding( - padding: EdgeInsets.only(top: 10.0), - child: StreamBuilder( - stream: conversationsBloc.conversations, - builder: (context, AsyncSnapshot> snapshot) { - if (snapshot.hasData) { - return buildList(snapshot.data); - } else if (snapshot.hasError) { - return Text(snapshot.error.toString()); - } - return Center(child: CircularProgressIndicator()); - })); - } - - Widget buildList(List data) { - return ListView.builder( - padding: EdgeInsets.only(top: 0.0), - itemCount: data.length, - itemBuilder: (context, index) { - return ConversationItem(conversation: data[index]); - }, - ); - } -} diff --git a/lib/src/ui/home/widgets/conversation_view.dart b/lib/src/ui/home/widgets/conversation_view.dart new file mode 100644 index 0000000..b3fbfdf --- /dev/null +++ b/lib/src/ui/home/widgets/conversation_view.dart @@ -0,0 +1,65 @@ +import "package:flutter/material.dart"; + +import "../../../models/conversation_model.dart"; +import "../../../blocs/conversation_bloc.dart"; + +import "conversation_item.dart"; +import "search_input.dart"; + +class ConversationView extends StatefulWidget { + @override + State createState() { + return _ConversationViewState(); + } +} + +class _ConversationViewState extends State { + final searchController = TextEditingController(); + + @override + initState() { + super.initState(); + conversationsBloc.fetchConversations(); + } + + @override + dispose() { + searchController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Padding( + padding: EdgeInsets.only(top: 10.0), + child: Column(mainAxisSize: MainAxisSize.min, children: [ + Padding( + padding: EdgeInsets.only(left: 20.0, right: 20.0, bottom: 10.0), + child: SearchInput( + controller: searchController, + hintText: "Search for messages or users")), + Flexible( + child: StreamBuilder( + stream: conversationsBloc.conversations, + builder: + (context, AsyncSnapshot> snapshot) { + if (snapshot.hasData) { + return buildList(snapshot.data); + } else if (snapshot.hasError) { + return Text(snapshot.error.toString()); + } + return Center(child: CircularProgressIndicator()); + })) + ])); + } + + Widget buildList(List data) { + return ListView.builder( + padding: EdgeInsets.only(top: 0.0), + itemCount: data.length, + itemBuilder: (context, index) { + return ConversationItem(conversation: data[index]); + }, + ); + } +} diff --git a/lib/src/ui/home/widgets/search_input.dart b/lib/src/ui/home/widgets/search_input.dart new file mode 100644 index 0000000..577ab7f --- /dev/null +++ b/lib/src/ui/home/widgets/search_input.dart @@ -0,0 +1,41 @@ +import "package:flutter/material.dart"; + +class SearchInput extends StatelessWidget { + final TextEditingController controller; + final String hintText; + + SearchInput({@required this.controller, @required this.hintText}); + + @override + Widget build(BuildContext context) { + return Container( + child: Padding( + padding: EdgeInsets.only(left: 10.0, right: 10.0), + child: Row(mainAxisAlignment: MainAxisAlignment.center, children: < + Widget>[ + Padding( + padding: EdgeInsets.only(right: 5.0), + child: Icon(Icons.search, color: Colors.grey[500])), + Flexible( + child: TextField( + controller: controller, + autocorrect: false, + cursorWidth: 2.0, + cursorColor: Colors.grey[500], + style: Theme.of(context).textTheme.body2.copyWith( + color: Colors.grey[500], fontWeight: FontWeight.w300), + decoration: InputDecoration( + border: InputBorder.none, + filled: false, + hintText: hintText, + hintStyle: Theme.of(context).textTheme.body2.copyWith( + color: Colors.grey[500], + fontWeight: FontWeight.w300, + )))), + ])), + decoration: BoxDecoration( + color: Colors.grey[200], + borderRadius: BorderRadius.all(Radius.circular(10.00)), + )); + } +} diff --git a/lib/src/ui/home/widgets/top_bar.dart b/lib/src/ui/home/widgets/top_bar.dart index db07e59..12b483d 100644 --- a/lib/src/ui/home/widgets/top_bar.dart +++ b/lib/src/ui/home/widgets/top_bar.dart @@ -2,83 +2,42 @@ import "package:flutter/material.dart"; class TopBar extends StatelessWidget { final String title; - final int pageNumber; - final double barHeight = 100.0; final String logo = "assets/logo.png"; - TopBar({@required this.title, @required this.pageNumber}); + TopBar({@required this.title}); @override Widget build(BuildContext context) { final double statusbarHeight = MediaQuery.of(context).padding.top; - // TODO: Fix cropping by moving onto stack, refactor widget into smaller parts return Material( type: MaterialType.canvas, - elevation: 10.0, + elevation: 5.0, child: Container( - padding: EdgeInsets.only(top: statusbarHeight, bottom: 10.0), + padding: EdgeInsets.only(top: statusbarHeight, bottom: 2.0), child: Material( type: MaterialType.transparency, - elevation: 10.0, + elevation: 0.0, color: Colors.transparent, child: Column(children: [ - Stack(alignment: Alignment.center, children: [ - Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Padding( - padding: EdgeInsets.only(left: 10.0), - child: Image.asset(logo, - semanticLabel: "Beep Logo", - width: 24.0, - height: 24.0)), - Spacer(), - IconButton(icon: Icon(Icons.search), onPressed: () {}), - IconButton( - icon: Icon(Icons.add_comment), onPressed: () {}) - ], - ), - Positioned( - child: Text(title, - style: Theme.of(context).accentTextTheme.display1)), - ]), Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Opacity( - opacity: (pageNumber == 0) ? 1.0 : 0.6, - child: Padding( - padding: EdgeInsets.only(left: 5.0), - child: Container( - width: 5.0, - height: 5.0, - decoration: BoxDecoration( - color: Colors.white, - shape: BoxShape.circle)))), - Opacity( - opacity: (pageNumber == 1) ? 1.0 : 0.6, - child: Padding( - padding: EdgeInsets.only(left: 5.0), - child: Container( - width: 5.0, - height: 5.0, - decoration: BoxDecoration( - color: Colors.white, - shape: BoxShape.circle)))), - Opacity( - opacity: (pageNumber == 2) ? 1.0 : 0.6, - child: Padding( - padding: EdgeInsets.only(left: 5.0), - child: Container( - width: 5.0, - height: 5.0, - decoration: BoxDecoration( - color: Colors.white, - shape: BoxShape.circle)))), - ]), + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Padding( + padding: EdgeInsets.only(left: 13.0), + child: Text("Edit", + style: Theme.of(context) + .accentTextTheme + .display2 + .copyWith(fontWeight: FontWeight.w400))), + Spacer(), + Text(title, + style: Theme.of(context).accentTextTheme.display1), + Spacer(), + IconButton(icon: Icon(Icons.add_comment), onPressed: () {}) + ], + ), ])), decoration: BoxDecoration( gradient: LinearGradient( diff --git a/lib/themer.dart b/lib/themer.dart index 220bc01..a5c0ef0 100644 --- a/lib/themer.dart +++ b/lib/themer.dart @@ -38,7 +38,7 @@ TextTheme buildTextTheme(TextTheme base) { title: base.title.copyWith(fontSize: 18.0, fontWeight: FontWeight.w500), subtitle: base.subtitle - .copyWith(fontSize: 12.0, fontWeight: FontWeight.w300), + .copyWith(fontSize: 14.0, fontWeight: FontWeight.w300), body2: base.body2.copyWith(fontSize: 16.0, fontWeight: FontWeight.w600), body1: