From f8acdeb4f37c6c8a04809fd5b52517b7a6029ba9 Mon Sep 17 00:00:00 2001 From: Sudharshan Date: Thu, 13 Jun 2019 16:00:55 +0800 Subject: [PATCH 01/24] feat: adding some new UI widgets, search bar, and tab navigation --- lib/src/ui/bottom_bar/bottom_bar.dart | 4 +- lib/src/ui/home/home.dart | 106 +++++++++++------- .../{contact_list.dart => contact_view.dart} | 6 +- .../ui/home/widgets/conversation_item.dart | 4 +- .../ui/home/widgets/conversation_list.dart | 47 -------- .../ui/home/widgets/conversation_view.dart | 65 +++++++++++ lib/src/ui/home/widgets/search_input.dart | 41 +++++++ lib/src/ui/home/widgets/top_bar.dart | 83 ++++---------- lib/themer.dart | 2 +- 9 files changed, 202 insertions(+), 156 deletions(-) rename lib/src/ui/home/widgets/{contact_list.dart => contact_view.dart} (88%) delete mode 100644 lib/src/ui/home/widgets/conversation_list.dart create mode 100644 lib/src/ui/home/widgets/conversation_view.dart create mode 100644 lib/src/ui/home/widgets/search_input.dart 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: From cac36abccc941e7e4520c192ab337b58ffd50853 Mon Sep 17 00:00:00 2001 From: Sudharshan Date: Thu, 13 Jun 2019 16:39:55 +0800 Subject: [PATCH 02/24] chore: getting started on contacts page --- lib/src/ui/home/home.dart | 2 +- lib/src/ui/home/widgets/top_bar.dart | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/src/ui/home/home.dart b/lib/src/ui/home/home.dart index 4b520af..8f6cdd3 100644 --- a/lib/src/ui/home/home.dart +++ b/lib/src/ui/home/home.dart @@ -111,7 +111,7 @@ class _HomeState extends State with SingleTickerProviderStateMixin { ], ); }, - child: Icon(data), + child: Icon(data, size: 30.0), ) : Icon(data, color: Colors.grey), title: Container(), diff --git a/lib/src/ui/home/widgets/top_bar.dart b/lib/src/ui/home/widgets/top_bar.dart index 12b483d..2a198de 100644 --- a/lib/src/ui/home/widgets/top_bar.dart +++ b/lib/src/ui/home/widgets/top_bar.dart @@ -1,5 +1,7 @@ import "package:flutter/material.dart"; +import "search_input.dart"; + class TopBar extends StatelessWidget { final String title; final String logo = "assets/logo.png"; From df4fca461a95558ea11fc6542346e7d24771aa22 Mon Sep 17 00:00:00 2001 From: Sudharshan Date: Thu, 13 Jun 2019 20:35:38 +0800 Subject: [PATCH 03/24] feat: populating the contact stuff --- lib/src/ui/home/widgets/contact_item.dart | 45 ++++++----- lib/src/ui/home/widgets/contact_view.dart | 76 +++++++++++++++++-- .../ui/home/widgets/conversation_item.dart | 6 +- pubspec.yaml | 1 + 4 files changed, 100 insertions(+), 28 deletions(-) diff --git a/lib/src/ui/home/widgets/contact_item.dart b/lib/src/ui/home/widgets/contact_item.dart index cb8af16..80e7792 100644 --- a/lib/src/ui/home/widgets/contact_item.dart +++ b/lib/src/ui/home/widgets/contact_item.dart @@ -10,24 +10,31 @@ class ContactItem extends StatelessWidget { @override Widget build(BuildContext context) { - return ListTile( - contentPadding: - EdgeInsets.only(top: 0.0, left: 20.0, right: 20.0, bottom: 0.0), - leading: Row(mainAxisSize: MainAxisSize.min, children: [ - /*Icon(Icons.star, color: Theme.of(context).primaryColorDark),*/ - Text("A", - style: TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.w700, - color: Theme.of(context).primaryColorDark)), - UserAvatar( - user: user, radius: 22.0, padding: EdgeInsets.only(left: 20.0)) - ]), - title: Text(user.firstName + " " + user.lastName, - style: Theme.of(context).textTheme.display2, - overflow: TextOverflow.ellipsis), - subtitle: Text("Last seen just now", - style: Theme.of(context).textTheme.subtitle), - onTap: () => {}); + return Container( + padding: EdgeInsets.only(top: 10.0, bottom: 10.0), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + UserAvatar( + user: user, + radius: 22.0, + padding: EdgeInsets.only(left: 20.0)), + Padding( + padding: EdgeInsets.only(left: 15.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(user.firstName + " " + user.lastName, + style: Theme.of(context).textTheme.display2, + overflow: TextOverflow.ellipsis), + Padding( + padding: EdgeInsets.only(top: 2), + child: Text("Last seen x ago", + style: Theme.of(context) + .textTheme + .subtitle + .copyWith(color: Color(0xFF455A64)))), + ])) + ])); } } diff --git a/lib/src/ui/home/widgets/contact_view.dart b/lib/src/ui/home/widgets/contact_view.dart index fd585b6..4647e87 100644 --- a/lib/src/ui/home/widgets/contact_view.dart +++ b/lib/src/ui/home/widgets/contact_view.dart @@ -1,4 +1,5 @@ import "package:flutter/material.dart"; +import 'package:sticky_headers/sticky_headers.dart'; import "../../../models/user_model.dart"; import "../../../blocs/contact_bloc.dart"; @@ -34,12 +35,73 @@ class _ContactViewState extends State { } Widget buildList(AsyncSnapshot> snapshot) { - return ListView.builder( - padding: EdgeInsets.only(top: 0.0), - itemCount: snapshot.data.length, - itemBuilder: (context, index) { - return ContactItem(user: snapshot.data[index]); - }, - ); + final Map> sortedList = { + "A": null, + "B": null, + "C": null, + "D": null, + "E": null, + "F": null, + "G": null, + "H": null, + "I": null, + "J": null, + "K": null, + "L": null, + "M": null, + "N": null, + "O": null, + "P": null, + "Q": null, + "R": null, + "S": null, + "T": null, + "U": null, + "V": null, + "W": null, + "X": null, + "Y": null, + "Z": null + }; + + // Sort the list into alphabets + sortedList.forEach((letter, list) { + sortedList[letter] = snapshot.data + .where((user) => user.firstName.startsWith(letter)) + .toList(); + }); + + print(sortedList); + + return ListView( + children: sortedList.entries.map((entry) { + if (entry.value.length == 0) { + return Container(); + } + + return Column(mainAxisSize: MainAxisSize.min, children: [ + StickyHeader( + header: Container( + height: 25.0, + color: Colors.grey[200], + padding: EdgeInsets.symmetric(horizontal: 20.0), + alignment: Alignment.centerLeft, + child: Text( + entry.key, + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.w700, + color: Theme.of(context).primaryColorDark), + ), + ), + content: ListView.builder( + padding: EdgeInsets.only(top: 0.0), + shrinkWrap: true, + itemCount: entry.value.length, + itemBuilder: (context, index) { + return ContactItem(user: entry.value[index]); + })) + ]); + }).toList()); } } diff --git a/lib/src/ui/home/widgets/conversation_item.dart b/lib/src/ui/home/widgets/conversation_item.dart index 6d0e39a..07bc078 100644 --- a/lib/src/ui/home/widgets/conversation_item.dart +++ b/lib/src/ui/home/widgets/conversation_item.dart @@ -75,8 +75,10 @@ class _ConversationItemState extends State { "I might have forgotten to close the windows", maxLines: 2, overflow: TextOverflow.ellipsis, - style: - Theme.of(context).textTheme.subtitle)), + style: Theme.of(context) + .textTheme + .subtitle + .copyWith(color: Color(0xFF455A64)))), StreamBuilder( stream: bloc.members, builder: (context, diff --git a/pubspec.yaml b/pubspec.yaml index 09a91e1..4d39eeb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,6 +16,7 @@ dependencies: shared_preferences: ^0.5.1 sqflite: ^1.1.0 eventsource: ^0.2.1 + sticky_headers: ^0.1.7 dev_dependencies: flutter_test: From 075d93457640df6c10092aea43f64cd454cb5335 Mon Sep 17 00:00:00 2001 From: Sudharshan Date: Thu, 13 Jun 2019 20:58:55 +0800 Subject: [PATCH 04/24] feat: adding search in contacts --- lib/src/ui/home/widgets/contact_view.dart | 26 ++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/lib/src/ui/home/widgets/contact_view.dart b/lib/src/ui/home/widgets/contact_view.dart index 4647e87..87f8521 100644 --- a/lib/src/ui/home/widgets/contact_view.dart +++ b/lib/src/ui/home/widgets/contact_view.dart @@ -5,6 +5,7 @@ import "../../../models/user_model.dart"; import "../../../blocs/contact_bloc.dart"; import "contact_item.dart"; +import "search_input.dart"; class ContactView extends StatefulWidget { @override @@ -14,12 +15,20 @@ class ContactView extends StatefulWidget { } class _ContactViewState extends State { + final searchController = TextEditingController(); + @override void initState() { super.initState(); contactBloc.fetchContacts(); } + @override + void dispose() { + searchController.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { return StreamBuilder( @@ -71,10 +80,8 @@ class _ContactViewState extends State { .toList(); }); - print(sortedList); - - return ListView( - children: sortedList.entries.map((entry) { + // Create list of children + final children = sortedList.entries.map((entry) { if (entry.value.length == 0) { return Container(); } @@ -95,6 +102,7 @@ class _ContactViewState extends State { ), ), content: ListView.builder( + physics: const NeverScrollableScrollPhysics(), padding: EdgeInsets.only(top: 0.0), shrinkWrap: true, itemCount: entry.value.length, @@ -102,6 +110,14 @@ class _ContactViewState extends State { return ContactItem(user: entry.value[index]); })) ]); - }).toList()); + }).toList(); + + children.insertAll(0, [ + Padding( + padding: EdgeInsets.only(left: 10.0, right: 10.0, bottom: 10.0), + child: SearchInput( + controller: searchController, hintText: "Search for people")), + ]); + return ListView(children: children); } } From 9ba9ab6487ff3e601af6f749258294d560f07882 Mon Sep 17 00:00:00 2001 From: Sudharshan Date: Fri, 14 Jun 2019 08:09:47 +0800 Subject: [PATCH 05/24] feat: added invite friends button --- lib/src/ui/home/widgets/contact_item.dart | 2 +- lib/src/ui/home/widgets/contact_view.dart | 22 ++++++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/lib/src/ui/home/widgets/contact_item.dart b/lib/src/ui/home/widgets/contact_item.dart index 80e7792..52b7709 100644 --- a/lib/src/ui/home/widgets/contact_item.dart +++ b/lib/src/ui/home/widgets/contact_item.dart @@ -18,7 +18,7 @@ class ContactItem extends StatelessWidget { UserAvatar( user: user, radius: 22.0, - padding: EdgeInsets.only(left: 20.0)), + padding: EdgeInsets.only(left: 15.0)), Padding( padding: EdgeInsets.only(left: 15.0), child: Column( diff --git a/lib/src/ui/home/widgets/contact_view.dart b/lib/src/ui/home/widgets/contact_view.dart index 87f8521..62819c3 100644 --- a/lib/src/ui/home/widgets/contact_view.dart +++ b/lib/src/ui/home/widgets/contact_view.dart @@ -91,7 +91,7 @@ class _ContactViewState extends State { header: Container( height: 25.0, color: Colors.grey[200], - padding: EdgeInsets.symmetric(horizontal: 20.0), + padding: EdgeInsets.symmetric(horizontal: 15.0), alignment: Alignment.centerLeft, child: Text( entry.key, @@ -114,9 +114,23 @@ class _ContactViewState extends State { children.insertAll(0, [ Padding( - padding: EdgeInsets.only(left: 10.0, right: 10.0, bottom: 10.0), - child: SearchInput( - controller: searchController, hintText: "Search for people")), + padding: EdgeInsets.only(left: 15.0, right: 15.0), + child: Column(mainAxisSize: MainAxisSize.min, children: [ + SearchInput( + controller: searchController, hintText: "Search for people"), + Padding( + padding: EdgeInsets.only(top: 5.0, bottom: 5.0), + child: Row(children: [ + Icon(Icons.people_outline, + color: Theme.of(context).primaryColorDark, size: 40.0), + Padding( + padding: EdgeInsets.only(left: 20.0), + child: Text("Invite Friends", + style: Theme.of(context).textTheme.display1.copyWith( + color: Theme.of(context).primaryColorDark, + fontWeight: FontWeight.w400))), + ])), + ])), ]); return ListView(children: children); } From 91148a77d07a60b213f0f4335179a53613eeb02b Mon Sep 17 00:00:00 2001 From: Sudharshan Date: Fri, 14 Jun 2019 08:18:14 +0800 Subject: [PATCH 06/24] fix: padding on top of contact search --- lib/main.dart | 3 ++- lib/src/ui/home/widgets/contact_view.dart | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index a399de0..e0e19a9 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,8 +1,9 @@ import "package:flutter/services.dart"; import 'routes.dart'; -import "src/blocs/heartbeat_bloc.dart"; +// import 'package:flutter/rendering.dart'; void main() { + // debugPaintSizeEnabled = true; SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light); Routes(); } diff --git a/lib/src/ui/home/widgets/contact_view.dart b/lib/src/ui/home/widgets/contact_view.dart index 62819c3..e52d0cb 100644 --- a/lib/src/ui/home/widgets/contact_view.dart +++ b/lib/src/ui/home/widgets/contact_view.dart @@ -132,6 +132,6 @@ class _ContactViewState extends State { ])), ])), ]); - return ListView(children: children); + return ListView(padding: EdgeInsets.only(top: 10.0), children: children); } } From 7269c1aad56fcfa06ecb2f49104002e789a9983e Mon Sep 17 00:00:00 2001 From: Sudharshan Date: Fri, 14 Jun 2019 08:41:49 +0800 Subject: [PATCH 07/24] feat: dynamic nav bar based on tab --- lib/src/ui/home/home.dart | 3 +-- .../ui/home/widgets/conversation_item.dart | 2 +- lib/src/ui/home/widgets/top_bar.dart | 23 +++++++++++++++---- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/lib/src/ui/home/home.dart b/lib/src/ui/home/home.dart index 8f6cdd3..bade7a8 100644 --- a/lib/src/ui/home/home.dart +++ b/lib/src/ui/home/home.dart @@ -20,7 +20,6 @@ class _HomeState extends State with SingleTickerProviderStateMixin { final conversationManager = ConversationManager(); // Bottom Bar navigation - final List titleList = ["Contacts", "Conversations", "Settings"]; int _tabNumber = 1; List itemsList = [ Icons.contacts, @@ -75,7 +74,7 @@ class _HomeState extends State with SingleTickerProviderStateMixin { return Scaffold( key: _scaffoldKey, body: Column(children: [ - TopBar(title: titleList[_tabNumber]), + TopBar(state: _tabNumber), Expanded( child: TabBarView( physics: NeverScrollableScrollPhysics(), diff --git a/lib/src/ui/home/widgets/conversation_item.dart b/lib/src/ui/home/widgets/conversation_item.dart index 07bc078..4c43d05 100644 --- a/lib/src/ui/home/widgets/conversation_item.dart +++ b/lib/src/ui/home/widgets/conversation_item.dart @@ -41,7 +41,7 @@ class _ConversationItemState extends State { Widget build(BuildContext context) { return Material( type: MaterialType.transparency, - elevation: 0, + elevation: 1, child: InkWell( onTap: () async { await bus.publish( diff --git a/lib/src/ui/home/widgets/top_bar.dart b/lib/src/ui/home/widgets/top_bar.dart index 2a198de..5ff5c2e 100644 --- a/lib/src/ui/home/widgets/top_bar.dart +++ b/lib/src/ui/home/widgets/top_bar.dart @@ -3,10 +3,11 @@ import "package:flutter/material.dart"; import "search_input.dart"; class TopBar extends StatelessWidget { - final String title; + final int state; final String logo = "assets/logo.png"; + final List titleList = ["Contacts", "Conversations", "Settings"]; - TopBar({@required this.title}); + TopBar({@required this.state}); @override Widget build(BuildContext context) { @@ -16,7 +17,7 @@ class TopBar extends StatelessWidget { type: MaterialType.canvas, elevation: 5.0, child: Container( - padding: EdgeInsets.only(top: statusbarHeight, bottom: 2.0), + padding: EdgeInsets.only(top: statusbarHeight, bottom: 0), child: Material( type: MaterialType.transparency, elevation: 0.0, @@ -34,10 +35,22 @@ class TopBar extends StatelessWidget { .display2 .copyWith(fontWeight: FontWeight.w400))), Spacer(), - Text(title, + Text(titleList[state], style: Theme.of(context).accentTextTheme.display1), Spacer(), - IconButton(icon: Icon(Icons.add_comment), onPressed: () {}) + (state == 1) + ? IconButton( + icon: Icon(Icons.add_comment), onPressed: () {}) + : Container(), + (state == 0) + ? IconButton(icon: Icon(Icons.add), onPressed: () {}) + : Container(), + (state == 2) + ? Opacity( + opacity: 0.0, + child: IconButton( + icon: Icon(Icons.edit), onPressed: () {})) + : Container(), ], ), ])), From 94ed8227f8ccafcd373b820f9d6e5c2c92b13ed9 Mon Sep 17 00:00:00 2001 From: Sudharshan Date: Fri, 14 Jun 2019 08:47:04 +0800 Subject: [PATCH 08/24] fix: scrolling searchbar with conversation view --- .../ui/home/widgets/conversation_view.dart | 39 +++++++++---------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/lib/src/ui/home/widgets/conversation_view.dart b/lib/src/ui/home/widgets/conversation_view.dart index b3fbfdf..cdf7bfb 100644 --- a/lib/src/ui/home/widgets/conversation_view.dart +++ b/lib/src/ui/home/widgets/conversation_view.dart @@ -30,32 +30,29 @@ class _ConversationViewState extends State { @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()); - })) - ])); + return ListView(padding: EdgeInsets.only(top: 10.0), children: [ + Padding( + padding: EdgeInsets.only(left: 20.0, right: 20.0, bottom: 10.0), + child: SearchInput( + controller: searchController, + hintText: "Search for messages or users")), + 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), + shrinkWrap: true, itemCount: data.length, itemBuilder: (context, index) { return ConversationItem(conversation: data[index]); From c12a850b5805ea91f741a690685cbdc2c5beeda4 Mon Sep 17 00:00:00 2001 From: Sudharshan Date: Fri, 14 Jun 2019 10:04:55 +0800 Subject: [PATCH 09/24] refactor: restructuring directories to support nested navigators in tabs --- .../{home/widgets => contact_view}/contact_view.dart | 8 ++++---- .../{home => contact_view}/widgets/contact_item.dart | 0 .../conversation_view.dart | 8 ++++---- .../widgets/conversation_item.dart | 0 lib/src/ui/{home => }/home.dart | 12 ++++++------ lib/src/ui/{home => }/widgets/search_input.dart | 0 lib/src/ui/{home => }/widgets/top_bar.dart | 0 7 files changed, 14 insertions(+), 14 deletions(-) rename lib/src/ui/{home/widgets => contact_view}/contact_view.dart (96%) rename lib/src/ui/{home => contact_view}/widgets/contact_item.dart (100%) rename lib/src/ui/{home/widgets => conversation_view}/conversation_view.dart (89%) rename lib/src/ui/{home => conversation_view}/widgets/conversation_item.dart (100%) rename lib/src/ui/{home => }/home.dart (92%) rename lib/src/ui/{home => }/widgets/search_input.dart (100%) rename lib/src/ui/{home => }/widgets/top_bar.dart (100%) diff --git a/lib/src/ui/home/widgets/contact_view.dart b/lib/src/ui/contact_view/contact_view.dart similarity index 96% rename from lib/src/ui/home/widgets/contact_view.dart rename to lib/src/ui/contact_view/contact_view.dart index e52d0cb..dc47df6 100644 --- a/lib/src/ui/home/widgets/contact_view.dart +++ b/lib/src/ui/contact_view/contact_view.dart @@ -1,11 +1,11 @@ import "package:flutter/material.dart"; import 'package:sticky_headers/sticky_headers.dart'; -import "../../../models/user_model.dart"; -import "../../../blocs/contact_bloc.dart"; +import "../../models/user_model.dart"; +import "../../blocs/contact_bloc.dart"; -import "contact_item.dart"; -import "search_input.dart"; +import "./widgets/contact_item.dart"; +import "../widgets/search_input.dart"; class ContactView extends StatefulWidget { @override diff --git a/lib/src/ui/home/widgets/contact_item.dart b/lib/src/ui/contact_view/widgets/contact_item.dart similarity index 100% rename from lib/src/ui/home/widgets/contact_item.dart rename to lib/src/ui/contact_view/widgets/contact_item.dart diff --git a/lib/src/ui/home/widgets/conversation_view.dart b/lib/src/ui/conversation_view/conversation_view.dart similarity index 89% rename from lib/src/ui/home/widgets/conversation_view.dart rename to lib/src/ui/conversation_view/conversation_view.dart index cdf7bfb..b5fc11d 100644 --- a/lib/src/ui/home/widgets/conversation_view.dart +++ b/lib/src/ui/conversation_view/conversation_view.dart @@ -1,10 +1,10 @@ import "package:flutter/material.dart"; -import "../../../models/conversation_model.dart"; -import "../../../blocs/conversation_bloc.dart"; +import "../../models/conversation_model.dart"; +import "../../blocs/conversation_bloc.dart"; -import "conversation_item.dart"; -import "search_input.dart"; +import "./widgets/conversation_item.dart"; +import "../widgets/search_input.dart"; class ConversationView extends StatefulWidget { @override diff --git a/lib/src/ui/home/widgets/conversation_item.dart b/lib/src/ui/conversation_view/widgets/conversation_item.dart similarity index 100% rename from lib/src/ui/home/widgets/conversation_item.dart rename to lib/src/ui/conversation_view/widgets/conversation_item.dart diff --git a/lib/src/ui/home/home.dart b/lib/src/ui/home.dart similarity index 92% rename from lib/src/ui/home/home.dart rename to lib/src/ui/home.dart index bade7a8..193d507 100644 --- a/lib/src/ui/home/home.dart +++ b/lib/src/ui/home.dart @@ -2,12 +2,12 @@ import "package:flutter/material.dart"; import 'dart:ui' as ui; import "./widgets/top_bar.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 "./conversation_view/conversation_view.dart"; +import "./contact_view/contact_view.dart"; +import "./bottom_bar/bottom_bar.dart"; +import "../services/heartbeat_manager.dart"; +import "../services/conversation_manager.dart"; +import "../blocs/message_bloc.dart"; class Home extends StatefulWidget { @override diff --git a/lib/src/ui/home/widgets/search_input.dart b/lib/src/ui/widgets/search_input.dart similarity index 100% rename from lib/src/ui/home/widgets/search_input.dart rename to lib/src/ui/widgets/search_input.dart diff --git a/lib/src/ui/home/widgets/top_bar.dart b/lib/src/ui/widgets/top_bar.dart similarity index 100% rename from lib/src/ui/home/widgets/top_bar.dart rename to lib/src/ui/widgets/top_bar.dart From 2638fede0b7b78203a0c6cd83452d601cac9cae6 Mon Sep 17 00:00:00 2001 From: Sudharshan Date: Fri, 14 Jun 2019 10:48:38 +0800 Subject: [PATCH 10/24] fix: making stuff smaller --- lib/routes.dart | 2 +- .../widgets/conversation_active_view.dart | 8 ++-- .../widgets/conversation_inactive_view.dart | 3 ++ lib/src/ui/contact_view/contact_view.dart | 23 ++++------ .../ui/contact_view/widgets/contact_item.dart | 4 +- .../widgets/conversation_item.dart | 5 +- lib/src/ui/home.dart | 4 +- lib/src/ui/login/widgets/login_page.dart | 11 ++--- lib/src/ui/login/widgets/otp_page.dart | 11 ++--- lib/src/ui/login/widgets/phone_input.dart | 2 +- lib/src/ui/widgets/search_input.dart | 46 ++++++++++--------- lib/src/ui/widgets/top_bar.dart | 4 +- lib/themer.dart | 17 +++---- 13 files changed, 70 insertions(+), 70 deletions(-) diff --git a/lib/routes.dart b/lib/routes.dart index 8628be9..78076f2 100644 --- a/lib/routes.dart +++ b/lib/routes.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import 'src/ui/home/home.dart'; +import 'src/ui/home.dart'; import "src/ui/login/welcome.dart"; import 'themer.dart'; diff --git a/lib/src/ui/bottom_bar/widgets/conversation_active_view.dart b/lib/src/ui/bottom_bar/widgets/conversation_active_view.dart index 403171c..d115af1 100644 --- a/lib/src/ui/bottom_bar/widgets/conversation_active_view.dart +++ b/lib/src/ui/bottom_bar/widgets/conversation_active_view.dart @@ -47,8 +47,8 @@ class _ConversationActiveViewState extends State { print(users[0].id); setState(() { _users = users - .map((user) => - UserAvatar(padding: EdgeInsets.only(right: 5.0), user: user)) + .map((user) => UserAvatar( + radius: 18.0, padding: EdgeInsets.only(right: 5.0), user: user)) .toList(); }); }); @@ -67,8 +67,8 @@ class _ConversationActiveViewState extends State { crossAxisAlignment: CrossAxisAlignment.center, children: [ Container( - width: 22.0, - height: 22.0, + width: 15.0, + height: 15.0, decoration: BoxDecoration( color: Theme.of(context).indicatorColor, shape: BoxShape.circle)), diff --git a/lib/src/ui/bottom_bar/widgets/conversation_inactive_view.dart b/lib/src/ui/bottom_bar/widgets/conversation_inactive_view.dart index b57eabd..e0d97f2 100644 --- a/lib/src/ui/bottom_bar/widgets/conversation_inactive_view.dart +++ b/lib/src/ui/bottom_bar/widgets/conversation_inactive_view.dart @@ -13,12 +13,15 @@ class ConversationInactiveView extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.center, children: [ UserAvatar( + radius: 18, padding: EdgeInsets.only(right: 5.0), user: User("1", "Isaac", "Tay", "+65 91043593")), UserAvatar( + radius: 18, padding: EdgeInsets.only(right: 5.0), user: User("1", "Isaac", "Tay", "+65 91043593")), UserAvatar( + radius: 18, padding: EdgeInsets.only(right: 5.0), user: User("1", "Isaac", "Tay", "+65 91043593")) ]) diff --git a/lib/src/ui/contact_view/contact_view.dart b/lib/src/ui/contact_view/contact_view.dart index dc47df6..e73e0fb 100644 --- a/lib/src/ui/contact_view/contact_view.dart +++ b/lib/src/ui/contact_view/contact_view.dart @@ -89,17 +89,15 @@ class _ContactViewState extends State { return Column(mainAxisSize: MainAxisSize.min, children: [ StickyHeader( header: Container( - height: 25.0, + height: 20.0, color: Colors.grey[200], padding: EdgeInsets.symmetric(horizontal: 15.0), alignment: Alignment.centerLeft, - child: Text( - entry.key, - style: TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.w700, - color: Theme.of(context).primaryColorDark), - ), + child: Text(entry.key, + style: Theme.of(context) + .primaryTextTheme + .display1 + .copyWith(color: Theme.of(context).primaryColorDark)), ), content: ListView.builder( physics: const NeverScrollableScrollPhysics(), @@ -119,16 +117,15 @@ class _ContactViewState extends State { SearchInput( controller: searchController, hintText: "Search for people"), Padding( - padding: EdgeInsets.only(top: 5.0, bottom: 5.0), + padding: EdgeInsets.only(top: 10.0, bottom: 10.0), child: Row(children: [ Icon(Icons.people_outline, - color: Theme.of(context).primaryColorDark, size: 40.0), + color: Theme.of(context).primaryColorDark, size: 30.0), Padding( padding: EdgeInsets.only(left: 20.0), child: Text("Invite Friends", - style: Theme.of(context).textTheme.display1.copyWith( - color: Theme.of(context).primaryColorDark, - fontWeight: FontWeight.w400))), + style: Theme.of(context).textTheme.title.copyWith( + color: Theme.of(context).primaryColorDark))), ])), ])), ]); diff --git a/lib/src/ui/contact_view/widgets/contact_item.dart b/lib/src/ui/contact_view/widgets/contact_item.dart index 52b7709..7473225 100644 --- a/lib/src/ui/contact_view/widgets/contact_item.dart +++ b/lib/src/ui/contact_view/widgets/contact_item.dart @@ -17,7 +17,7 @@ class ContactItem extends StatelessWidget { children: [ UserAvatar( user: user, - radius: 22.0, + radius: 18.0, padding: EdgeInsets.only(left: 15.0)), Padding( padding: EdgeInsets.only(left: 15.0), @@ -25,7 +25,7 @@ class ContactItem extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(user.firstName + " " + user.lastName, - style: Theme.of(context).textTheme.display2, + style: Theme.of(context).textTheme.title, overflow: TextOverflow.ellipsis), Padding( padding: EdgeInsets.only(top: 2), diff --git a/lib/src/ui/conversation_view/widgets/conversation_item.dart b/lib/src/ui/conversation_view/widgets/conversation_item.dart index 4c43d05..6109e04 100644 --- a/lib/src/ui/conversation_view/widgets/conversation_item.dart +++ b/lib/src/ui/conversation_view/widgets/conversation_item.dart @@ -60,9 +60,8 @@ class _ConversationItemState extends State { Text("12:25 PM", style: Theme.of(context) .primaryTextTheme - .body1 + .display2 .copyWith( - fontWeight: FontWeight.w500, color: Theme.of(context).primaryColorDark)), ]), Padding( @@ -101,7 +100,7 @@ class _ConversationItemState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: data .map((user) => UserAvatar( - radius: 18.0, + radius: 16.0, padding: EdgeInsets.only(top: 0.0, left: 5.0), user: user)) .toList()); diff --git a/lib/src/ui/home.dart b/lib/src/ui/home.dart index 193d507..c68b871 100644 --- a/lib/src/ui/home.dart +++ b/lib/src/ui/home.dart @@ -110,9 +110,9 @@ class _HomeState extends State with SingleTickerProviderStateMixin { ], ); }, - child: Icon(data, size: 30.0), + child: Icon(data, size: 25.0), ) - : Icon(data, color: Colors.grey), + : Icon(data, color: Colors.grey, size: 20), title: Container(), ); }).toList()) diff --git a/lib/src/ui/login/widgets/login_page.dart b/lib/src/ui/login/widgets/login_page.dart index 1159dc7..ef08a02 100644 --- a/lib/src/ui/login/widgets/login_page.dart +++ b/lib/src/ui/login/widgets/login_page.dart @@ -41,12 +41,11 @@ class _LoginPageState extends State { Text("First things first.", textAlign: TextAlign.left, style: Theme.of(context).accentTextTheme.display3), - Text( - "Enter your phone number, to connect to your existing Beep account.", - style: Theme.of(context) - .accentTextTheme - .title - .copyWith(fontWeight: FontWeight.w400)), + Padding( + padding: EdgeInsets.only(top: 5.0), + child: Text( + "Enter your phone number, to connect to your existing Beep account.", + style: Theme.of(context).accentTextTheme.title)), Padding( padding: EdgeInsets.only(top: 20.0), child: PhoneInput(controller: controller)), diff --git a/lib/src/ui/login/widgets/otp_page.dart b/lib/src/ui/login/widgets/otp_page.dart index 5e354e2..e23cd2e 100644 --- a/lib/src/ui/login/widgets/otp_page.dart +++ b/lib/src/ui/login/widgets/otp_page.dart @@ -36,12 +36,11 @@ class _OtpPageState extends State { Text("Almost there.", textAlign: TextAlign.left, style: Theme.of(context).accentTextTheme.display3), - Text( - "I've sent an authentication code via SMS to your device, enter it below.", - style: Theme.of(context) - .accentTextTheme - .title - .copyWith(fontWeight: FontWeight.w400)), + Padding( + padding: EdgeInsets.only(top: 5.0), + child: Text( + "I've sent an authentication code via SMS to your device, enter it below.", + style: Theme.of(context).accentTextTheme.title)), Padding( padding: EdgeInsets.only(top: 20.0), child: Center( diff --git a/lib/src/ui/login/widgets/phone_input.dart b/lib/src/ui/login/widgets/phone_input.dart index b7b1652..b98732d 100644 --- a/lib/src/ui/login/widgets/phone_input.dart +++ b/lib/src/ui/login/widgets/phone_input.dart @@ -15,7 +15,7 @@ class PhoneInput extends StatelessWidget { width: 45, child: Center( child: Text("+65", - style: Theme.of(context).textTheme.body2.copyWith( + style: Theme.of(context).textTheme.title.copyWith( color: Theme.of(context).primaryColorDark))), decoration: BoxDecoration( color: Colors.white, diff --git a/lib/src/ui/widgets/search_input.dart b/lib/src/ui/widgets/search_input.dart index 577ab7f..4878d2c 100644 --- a/lib/src/ui/widgets/search_input.dart +++ b/lib/src/ui/widgets/search_input.dart @@ -11,28 +11,30 @@ class SearchInput extends StatelessWidget { 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, - )))), - ])), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + 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.subtitle.copyWith( + color: Colors.grey[500], + fontWeight: FontWeight.w300), + decoration: InputDecoration( + border: InputBorder.none, + filled: false, + hintText: hintText, + hintStyle: Theme.of(context) + .textTheme + .subtitle + .copyWith(color: Colors.grey[500])))), + ])), decoration: BoxDecoration( color: Colors.grey[200], borderRadius: BorderRadius.all(Radius.circular(10.00)), diff --git a/lib/src/ui/widgets/top_bar.dart b/lib/src/ui/widgets/top_bar.dart index 5ff5c2e..212e497 100644 --- a/lib/src/ui/widgets/top_bar.dart +++ b/lib/src/ui/widgets/top_bar.dart @@ -32,8 +32,8 @@ class TopBar extends StatelessWidget { child: Text("Edit", style: Theme.of(context) .accentTextTheme - .display2 - .copyWith(fontWeight: FontWeight.w400))), + .title + .copyWith(fontWeight: FontWeight.w300))), Spacer(), Text(titleList[state], style: Theme.of(context).accentTextTheme.display1), diff --git a/lib/themer.dart b/lib/themer.dart index a5c0ef0..0af5d81 100644 --- a/lib/themer.dart +++ b/lib/themer.dart @@ -31,16 +31,17 @@ TextTheme buildTextTheme(TextTheme base) { .copyWith(fontSize: 40.0, fontWeight: FontWeight.w600), display3: base.display3 .copyWith(fontSize: 30.0, fontWeight: FontWeight.w700), - display2: base.display2 - .copyWith(fontSize: 18.0, fontWeight: FontWeight.w500), - display1: base.display1 - .copyWith(fontSize: 19.0, fontWeight: FontWeight.w600), + display2: base.display2.copyWith( + fontSize: 12.0, fontWeight: FontWeight.w500), // Used for time + display1: base.display1.copyWith( + fontSize: 16.0, + fontWeight: FontWeight.w600), // Used for overall title title: - base.title.copyWith(fontSize: 18.0, fontWeight: FontWeight.w500), + base.title.copyWith(fontSize: 16.0, fontWeight: FontWeight.w500), subtitle: base.subtitle - .copyWith(fontSize: 14.0, fontWeight: FontWeight.w300), - body2: - base.body2.copyWith(fontSize: 16.0, fontWeight: FontWeight.w600), + .copyWith(fontSize: 13.0, fontWeight: FontWeight.w300), + body2: base.body2.copyWith( + fontSize: 12.0, fontWeight: FontWeight.w600), // Bold normal body1: base.body1.copyWith(fontSize: 12.0, fontWeight: FontWeight.w400)) .apply( From d86f4328ff18842cb218b0b11a5d4e496186b8fd Mon Sep 17 00:00:00 2001 From: Sudharshan Date: Fri, 14 Jun 2019 13:53:04 +0800 Subject: [PATCH 11/24] feat: adding nest navigators for each tab --- lib/src/ui/contact_tab/contact_tab.dart | 33 +++++++++++++++++++ .../widgets/contact_item.dart | 0 .../widgets/home_view.dart} | 14 ++++---- .../contact_tab/widgets/new_contact_view.dart | 0 .../ui/conversation_tab/conversation_tab.dart | 33 +++++++++++++++++++ .../widgets/conversation_item.dart | 0 .../widgets/conversation_view.dart | 0 .../widgets/home_view.dart} | 14 ++++---- .../widgets/new_conversation_view.dart | 0 lib/src/ui/home.dart | 8 ++--- 10 files changed, 84 insertions(+), 18 deletions(-) create mode 100644 lib/src/ui/contact_tab/contact_tab.dart rename lib/src/ui/{contact_view => contact_tab}/widgets/contact_item.dart (100%) rename lib/src/ui/{contact_view/contact_view.dart => contact_tab/widgets/home_view.dart} (92%) create mode 100644 lib/src/ui/contact_tab/widgets/new_contact_view.dart create mode 100644 lib/src/ui/conversation_tab/conversation_tab.dart rename lib/src/ui/{conversation_view => conversation_tab}/widgets/conversation_item.dart (100%) create mode 100644 lib/src/ui/conversation_tab/widgets/conversation_view.dart rename lib/src/ui/{conversation_view/conversation_view.dart => conversation_tab/widgets/home_view.dart} (81%) create mode 100644 lib/src/ui/conversation_tab/widgets/new_conversation_view.dart diff --git a/lib/src/ui/contact_tab/contact_tab.dart b/lib/src/ui/contact_tab/contact_tab.dart new file mode 100644 index 0000000..dc900f5 --- /dev/null +++ b/lib/src/ui/contact_tab/contact_tab.dart @@ -0,0 +1,33 @@ +import "package:flutter/material.dart"; + +import "./widgets/home_view.dart"; + +class ContactTab extends StatefulWidget { + @override + State createState() { + return _ContactTabState(); + } +} + +class _ContactTabState extends State { + @override + Widget build(BuildContext context) { + return Navigator( + initialRoute: "conversation/home", + onGenerateRoute: (RouteSettings settings) { + WidgetBuilder builder; + switch (settings.name) { + case "conversation/home": + builder = (BuildContext _) => HomeView(); + break; + case "conversation/new": + builder = (BuildContext _) => Center(child: Text("SOON")); + break; + default: + throw Exception("Invalid route: ${settings.name}"); + } + return MaterialPageRoute(builder: builder, settings: settings); + }, + ); + } +} diff --git a/lib/src/ui/contact_view/widgets/contact_item.dart b/lib/src/ui/contact_tab/widgets/contact_item.dart similarity index 100% rename from lib/src/ui/contact_view/widgets/contact_item.dart rename to lib/src/ui/contact_tab/widgets/contact_item.dart diff --git a/lib/src/ui/contact_view/contact_view.dart b/lib/src/ui/contact_tab/widgets/home_view.dart similarity index 92% rename from lib/src/ui/contact_view/contact_view.dart rename to lib/src/ui/contact_tab/widgets/home_view.dart index e73e0fb..58d96a9 100644 --- a/lib/src/ui/contact_view/contact_view.dart +++ b/lib/src/ui/contact_tab/widgets/home_view.dart @@ -1,20 +1,20 @@ import "package:flutter/material.dart"; import 'package:sticky_headers/sticky_headers.dart'; -import "../../models/user_model.dart"; -import "../../blocs/contact_bloc.dart"; +import "../../../models/user_model.dart"; +import "../../../blocs/contact_bloc.dart"; -import "./widgets/contact_item.dart"; -import "../widgets/search_input.dart"; +import "../widgets/contact_item.dart"; +import "../../widgets/search_input.dart"; -class ContactView extends StatefulWidget { +class HomeView extends StatefulWidget { @override State createState() { - return _ContactViewState(); + return _HomeViewState(); } } -class _ContactViewState extends State { +class _HomeViewState extends State { final searchController = TextEditingController(); @override diff --git a/lib/src/ui/contact_tab/widgets/new_contact_view.dart b/lib/src/ui/contact_tab/widgets/new_contact_view.dart new file mode 100644 index 0000000..e69de29 diff --git a/lib/src/ui/conversation_tab/conversation_tab.dart b/lib/src/ui/conversation_tab/conversation_tab.dart new file mode 100644 index 0000000..c6bdae7 --- /dev/null +++ b/lib/src/ui/conversation_tab/conversation_tab.dart @@ -0,0 +1,33 @@ +import "package:flutter/material.dart"; + +import "./widgets/home_view.dart"; + +class ConversationTab extends StatefulWidget { + @override + State createState() { + return _ConversationTabState(); + } +} + +class _ConversationTabState extends State { + @override + Widget build(BuildContext context) { + return Navigator( + initialRoute: "conversation/home", + onGenerateRoute: (RouteSettings settings) { + WidgetBuilder builder; + switch (settings.name) { + case "conversation/home": + builder = (BuildContext _) => HomeView(); + break; + case "conversation/new": + builder = (BuildContext _) => Center(child: Text("SOON")); + break; + default: + throw Exception("Invalid route: ${settings.name}"); + } + return MaterialPageRoute(builder: builder, settings: settings); + }, + ); + } +} diff --git a/lib/src/ui/conversation_view/widgets/conversation_item.dart b/lib/src/ui/conversation_tab/widgets/conversation_item.dart similarity index 100% rename from lib/src/ui/conversation_view/widgets/conversation_item.dart rename to lib/src/ui/conversation_tab/widgets/conversation_item.dart diff --git a/lib/src/ui/conversation_tab/widgets/conversation_view.dart b/lib/src/ui/conversation_tab/widgets/conversation_view.dart new file mode 100644 index 0000000..e69de29 diff --git a/lib/src/ui/conversation_view/conversation_view.dart b/lib/src/ui/conversation_tab/widgets/home_view.dart similarity index 81% rename from lib/src/ui/conversation_view/conversation_view.dart rename to lib/src/ui/conversation_tab/widgets/home_view.dart index b5fc11d..029ea61 100644 --- a/lib/src/ui/conversation_view/conversation_view.dart +++ b/lib/src/ui/conversation_tab/widgets/home_view.dart @@ -1,19 +1,19 @@ import "package:flutter/material.dart"; -import "../../models/conversation_model.dart"; -import "../../blocs/conversation_bloc.dart"; +import "../../../models/conversation_model.dart"; +import "../../../blocs/conversation_bloc.dart"; -import "./widgets/conversation_item.dart"; -import "../widgets/search_input.dart"; +import "../widgets/conversation_item.dart"; +import "../../widgets/search_input.dart"; -class ConversationView extends StatefulWidget { +class HomeView extends StatefulWidget { @override State createState() { - return _ConversationViewState(); + return _HomeViewState(); } } -class _ConversationViewState extends State { +class _HomeViewState extends State { final searchController = TextEditingController(); @override diff --git a/lib/src/ui/conversation_tab/widgets/new_conversation_view.dart b/lib/src/ui/conversation_tab/widgets/new_conversation_view.dart new file mode 100644 index 0000000..e69de29 diff --git a/lib/src/ui/home.dart b/lib/src/ui/home.dart index c68b871..7b8f823 100644 --- a/lib/src/ui/home.dart +++ b/lib/src/ui/home.dart @@ -2,8 +2,8 @@ import "package:flutter/material.dart"; import 'dart:ui' as ui; import "./widgets/top_bar.dart"; -import "./conversation_view/conversation_view.dart"; -import "./contact_view/contact_view.dart"; +import "./conversation_tab/conversation_tab.dart"; +import "./contact_tab/contact_tab.dart"; import "./bottom_bar/bottom_bar.dart"; import "../services/heartbeat_manager.dart"; import "../services/conversation_manager.dart"; @@ -80,8 +80,8 @@ class _HomeState extends State with SingleTickerProviderStateMixin { physics: NeverScrollableScrollPhysics(), controller: controller, children: [ - ContactView(), - ConversationView(), + ContactTab(), + ConversationTab(), Container(), ])), ]), From aef13f60b7746c729aacfb7082c272737d4e3f7d Mon Sep 17 00:00:00 2001 From: Sudharshan Date: Sat, 15 Jun 2019 07:26:18 +0800 Subject: [PATCH 12/24] changed the way conversation UI works --- .../contact_tab/widgets/new_contact_view.dart | 0 .../widgets/conversation_item.dart | 93 +++++++++---------- .../widgets/conversation_view.dart | 0 .../widgets/new_conversation_view.dart | 0 4 files changed, 46 insertions(+), 47 deletions(-) delete mode 100644 lib/src/ui/contact_tab/widgets/new_contact_view.dart delete mode 100644 lib/src/ui/conversation_tab/widgets/conversation_view.dart delete mode 100644 lib/src/ui/conversation_tab/widgets/new_conversation_view.dart diff --git a/lib/src/ui/contact_tab/widgets/new_contact_view.dart b/lib/src/ui/contact_tab/widgets/new_contact_view.dart deleted file mode 100644 index e69de29..0000000 diff --git a/lib/src/ui/conversation_tab/widgets/conversation_item.dart b/lib/src/ui/conversation_tab/widgets/conversation_item.dart index 6109e04..9ceb6b4 100644 --- a/lib/src/ui/conversation_tab/widgets/conversation_item.dart +++ b/lib/src/ui/conversation_tab/widgets/conversation_item.dart @@ -49,60 +49,59 @@ class _ConversationItemState extends State { }, child: Container( padding: EdgeInsets.only( - top: 5.0, left: 20.0, right: 20.0, bottom: 5.0), - child: Column(children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(conversation.title, - style: Theme.of(context).textTheme.title), - Spacer(), + top: 8.0, left: 10.0, right: 10.0, bottom: 8.0), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + StreamBuilder( + stream: bloc.members, + builder: + (context, AsyncSnapshot> snapshot) { + if (snapshot.hasData) { + return avatarBuilder(snapshot.data); + } else if (snapshot.hasError) { + return Text(snapshot.error.toString()); + } + return SizedBox(width: 18.0, height: 18.0); + }), + Expanded( + child: Container( + padding: EdgeInsets.only(left: 10.0, right: 5.0), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(conversation.title, + style: + Theme.of(context).textTheme.title), + Text("yaddaydaadadyasdhbsjdfhsbjdfhsbdug", + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: Theme.of(context) + .textTheme + .subtitle + .copyWith( + color: Color(0xFF455A64))), + ]))), + Column(mainAxisSize: MainAxisSize.min, children: [ Text("12:25 PM", style: Theme.of(context) .primaryTextTheme .display2 .copyWith( color: Theme.of(context).primaryColorDark)), - ]), - Padding( - padding: EdgeInsets.only(top: 5.0), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: Text( - "I might have forgotten to close the windows", - maxLines: 2, - overflow: TextOverflow.ellipsis, - style: Theme.of(context) - .textTheme - .subtitle - .copyWith(color: Color(0xFF455A64)))), - StreamBuilder( - stream: bloc.members, - builder: (context, - AsyncSnapshot> snapshot) { - if (snapshot.hasData) { - return membersBuilder(snapshot.data); - } else if (snapshot.hasError) { - return Text(snapshot.error.toString()); - } - return SizedBox(width: 18.0, height: 18.0); - }), - ])) - ])))); + ]) + ])))); } - Widget membersBuilder(List data) { - return Row( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.end, - crossAxisAlignment: CrossAxisAlignment.start, - children: data - .map((user) => UserAvatar( - radius: 16.0, - padding: EdgeInsets.only(top: 0.0, left: 5.0), - user: user)) - .toList()); + Widget avatarBuilder(List data) { + if (data.length == 1) { + return UserAvatar(radius: 25.0, user: data[0]); + } else if (data.length > 1) { + final groupUser = new User("0", conversation.title, "", ""); + return UserAvatar(radius: 25.0, user: groupUser); + } else { + return Container(); + } } } diff --git a/lib/src/ui/conversation_tab/widgets/conversation_view.dart b/lib/src/ui/conversation_tab/widgets/conversation_view.dart deleted file mode 100644 index e69de29..0000000 diff --git a/lib/src/ui/conversation_tab/widgets/new_conversation_view.dart b/lib/src/ui/conversation_tab/widgets/new_conversation_view.dart deleted file mode 100644 index e69de29..0000000 From 6cedd970b4e939ed8a9d2e256fa2b0b854772e0f Mon Sep 17 00:00:00 2001 From: Sudharshan Date: Sat, 15 Jun 2019 07:56:15 +0800 Subject: [PATCH 13/24] feat: prettier useravatar --- lib/src/ui/widgets/user_avatar.dart | 46 +++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/lib/src/ui/widgets/user_avatar.dart b/lib/src/ui/widgets/user_avatar.dart index c93a25d..e627041 100644 --- a/lib/src/ui/widgets/user_avatar.dart +++ b/lib/src/ui/widgets/user_avatar.dart @@ -1,4 +1,5 @@ import "package:flutter/material.dart"; +import 'dart:ui' as ui; import "dart:async"; import "../../models/user_model.dart"; @@ -42,19 +43,37 @@ class _UserAvatarState extends State { String lastName = (widget.user.lastName.isEmpty) ? '' : widget.user.lastName[0]; + final colors = _stringToColor(widget.user.lastName); + return Padding( padding: widget.padding, child: Stack(alignment: Alignment.bottomRight, children: [ - CircleAvatar( - backgroundColor: _stringToColor(widget.user.lastName), - child: Text( - firstName.toUpperCase() + lastName.toUpperCase(), - style: Theme.of(context) - .accentTextTheme - .title - .copyWith(fontSize: widget.radius / 1.2), - ), - radius: widget.radius), + Container( + height: (widget.radius * 2), + width: (widget.radius * 2), + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topRight, + end: Alignment.bottomLeft, + stops: [ + 0, + 1 + ], + colors: [ + colors[0], + colors[1], + ]), + borderRadius: + BorderRadius.all(Radius.circular(widget.radius))), + child: Center( + child: Text( + firstName.toUpperCase() + lastName.toUpperCase(), + style: Theme.of(context) + .accentTextTheme + .title + .copyWith(fontSize: widget.radius / 1.4), + ), + )), StreamBuilder( stream: heartbeatReceiverBloc.stream, builder: (context, AsyncSnapshot> snapshot) { @@ -84,7 +103,7 @@ class _UserAvatarState extends State { } // Hashing username into a pastel color - Color _stringToColor(String str) { + List _stringToColor(String str) { int hash = 0; str.runes.forEach((int rune) { @@ -93,6 +112,9 @@ class _UserAvatarState extends State { hash = hash % 360; - return HSLColor.fromAHSL(1.0, hash.toDouble(), 0.8, 0.4).toColor(); + return [ + HSLColor.fromAHSL(1.0, hash.toDouble(), 0.8, 0.4).toColor(), + HSLColor.fromAHSL(1.0, hash.toDouble(), 0.8, 0.5).toColor() + ]; } } From 7f529b090ee4bd96aa145c85b0c56d7b4f30b1b8 Mon Sep 17 00:00:00 2001 From: Sudharshan Date: Sat, 22 Jun 2019 16:41:00 +0800 Subject: [PATCH 14/24] feat: moved topbars into each view for customization --- lib/src/blocs/conversation_bloc.dart | 1 + lib/src/blocs/message_bloc.dart | 2 +- .../widgets/conversation_active_view.dart | 4 +- lib/src/ui/contact_tab/contact_tab.dart | 15 +++- lib/src/ui/contact_tab/widgets/home_view.dart | 79 +++++++++++-------- .../ui/conversation_tab/conversation_tab.dart | 1 - .../widgets/conversation_item.dart | 8 +- .../conversation_tab/widgets/home_view.dart | 52 ++++++++---- lib/src/ui/home.dart | 61 +++++++------- lib/src/ui/widgets/top_bar.dart | 53 ++++--------- 10 files changed, 149 insertions(+), 127 deletions(-) diff --git a/lib/src/blocs/conversation_bloc.dart b/lib/src/blocs/conversation_bloc.dart index befa150..e929e7c 100644 --- a/lib/src/blocs/conversation_bloc.dart +++ b/lib/src/blocs/conversation_bloc.dart @@ -13,6 +13,7 @@ class ConversationsBloc { fetchConversations() async { List conversationList = await _provider.fetchConversations(); + print(conversationList); _conversationsFetcher.sink.add(conversationList); } diff --git a/lib/src/blocs/message_bloc.dart b/lib/src/blocs/message_bloc.dart index 66c1601..c9d52c0 100644 --- a/lib/src/blocs/message_bloc.dart +++ b/lib/src/blocs/message_bloc.dart @@ -19,4 +19,4 @@ class MessageBloc { } // global instance for access throughout the app -final messageBloc = MessageBloc(); +final messageChannel = MessageBloc(); diff --git a/lib/src/ui/bottom_bar/widgets/conversation_active_view.dart b/lib/src/ui/bottom_bar/widgets/conversation_active_view.dart index d115af1..70c416a 100644 --- a/lib/src/ui/bottom_bar/widgets/conversation_active_view.dart +++ b/lib/src/ui/bottom_bar/widgets/conversation_active_view.dart @@ -18,7 +18,6 @@ class ConversationActiveView extends StatefulWidget { } class _ConversationActiveViewState extends State { - final bus = messageBloc; final conversationApiProvider = ConversationApiProvider(); Conversation _conversation; List _users; @@ -91,7 +90,8 @@ class _ConversationActiveViewState extends State { icon: Icon(Icons.close), onPressed: () async { // Call method to close connection - await bus.publish({"state": "disconnect"}); + await messageChannel + .publish({"target": "home", "state": "disconnect"}); print("Pressed close"); }), ]), diff --git a/lib/src/ui/contact_tab/contact_tab.dart b/lib/src/ui/contact_tab/contact_tab.dart index dc900f5..73c0773 100644 --- a/lib/src/ui/contact_tab/contact_tab.dart +++ b/lib/src/ui/contact_tab/contact_tab.dart @@ -1,6 +1,7 @@ import "package:flutter/material.dart"; import "./widgets/home_view.dart"; +import "../../blocs/message_bloc.dart"; class ContactTab extends StatefulWidget { @override @@ -10,17 +11,25 @@ class ContactTab extends StatefulWidget { } class _ContactTabState extends State { + final GlobalKey navigatorKey = + new GlobalKey(); + + @override + initState() { + super.initState(); + } + @override Widget build(BuildContext context) { return Navigator( - initialRoute: "conversation/home", + initialRoute: "contact/home", onGenerateRoute: (RouteSettings settings) { WidgetBuilder builder; switch (settings.name) { - case "conversation/home": + case "contact/home": builder = (BuildContext _) => HomeView(); break; - case "conversation/new": + case "contact/new": builder = (BuildContext _) => Center(child: Text("SOON")); break; default: diff --git a/lib/src/ui/contact_tab/widgets/home_view.dart b/lib/src/ui/contact_tab/widgets/home_view.dart index 58d96a9..fe47449 100644 --- a/lib/src/ui/contact_tab/widgets/home_view.dart +++ b/lib/src/ui/contact_tab/widgets/home_view.dart @@ -5,6 +5,7 @@ import "../../../models/user_model.dart"; import "../../../blocs/contact_bloc.dart"; import "../widgets/contact_item.dart"; +import "../../widgets/top_bar.dart"; import "../../widgets/search_input.dart"; class HomeView extends StatefulWidget { @@ -31,16 +32,51 @@ class _HomeViewState extends State { @override Widget build(BuildContext context) { - return StreamBuilder( - stream: contactBloc.contacts, - builder: (context, AsyncSnapshot> snapshot) { - if (snapshot.hasData) { - return buildList(snapshot); - } else if (snapshot.hasError) { - return Text(snapshot.error.toString()); - } - return Center(child: CircularProgressIndicator()); - }); + return Column(children: [ + TopBar(title: "Contacts", children: [ + Padding( + padding: EdgeInsets.only(left: 13.0), + child: Text("Edit", + style: Theme.of(context) + .accentTextTheme + .title + .copyWith(fontWeight: FontWeight.w300))), + Spacer(), + IconButton( + icon: Icon(Icons.add), + onPressed: () { + Navigator.pushNamed(context, "contact/new"); + }), + ]), + Padding( + padding: EdgeInsets.only(left: 15.0, right: 15.0, top: 10.0), + child: Column(mainAxisSize: MainAxisSize.min, children: [ + SearchInput( + controller: searchController, hintText: "Search for people"), + Padding( + padding: EdgeInsets.only(top: 10.0, bottom: 10.0), + child: Row(children: [ + Icon(Icons.people_outline, + color: Theme.of(context).primaryColorDark, size: 30.0), + Padding( + padding: EdgeInsets.only(left: 20.0), + child: Text("Invite Friends", + style: Theme.of(context).textTheme.title.copyWith( + color: Theme.of(context).primaryColorDark))), + ])), + ])), + Expanded( + child: StreamBuilder( + stream: contactBloc.contacts, + builder: (context, AsyncSnapshot> snapshot) { + if (snapshot.hasData) { + return buildList(snapshot); + } else if (snapshot.hasError) { + return Text(snapshot.error.toString()); + } + return Center(child: CircularProgressIndicator()); + })) + ]); } Widget buildList(AsyncSnapshot> snapshot) { @@ -89,7 +125,7 @@ class _HomeViewState extends State { return Column(mainAxisSize: MainAxisSize.min, children: [ StickyHeader( header: Container( - height: 20.0, + height: 21.0, color: Colors.grey[200], padding: EdgeInsets.symmetric(horizontal: 15.0), alignment: Alignment.centerLeft, @@ -110,25 +146,6 @@ class _HomeViewState extends State { ]); }).toList(); - children.insertAll(0, [ - Padding( - padding: EdgeInsets.only(left: 15.0, right: 15.0), - child: Column(mainAxisSize: MainAxisSize.min, children: [ - SearchInput( - controller: searchController, hintText: "Search for people"), - Padding( - padding: EdgeInsets.only(top: 10.0, bottom: 10.0), - child: Row(children: [ - Icon(Icons.people_outline, - color: Theme.of(context).primaryColorDark, size: 30.0), - Padding( - padding: EdgeInsets.only(left: 20.0), - child: Text("Invite Friends", - style: Theme.of(context).textTheme.title.copyWith( - color: Theme.of(context).primaryColorDark))), - ])), - ])), - ]); - return ListView(padding: EdgeInsets.only(top: 10.0), children: children); + return ListView(padding: EdgeInsets.only(top: 0.0), children: children); } } diff --git a/lib/src/ui/conversation_tab/conversation_tab.dart b/lib/src/ui/conversation_tab/conversation_tab.dart index c6bdae7..854a5df 100644 --- a/lib/src/ui/conversation_tab/conversation_tab.dart +++ b/lib/src/ui/conversation_tab/conversation_tab.dart @@ -1,5 +1,4 @@ import "package:flutter/material.dart"; - import "./widgets/home_view.dart"; class ConversationTab extends StatefulWidget { diff --git a/lib/src/ui/conversation_tab/widgets/conversation_item.dart b/lib/src/ui/conversation_tab/widgets/conversation_item.dart index 9ceb6b4..cff710e 100644 --- a/lib/src/ui/conversation_tab/widgets/conversation_item.dart +++ b/lib/src/ui/conversation_tab/widgets/conversation_item.dart @@ -20,7 +20,6 @@ class ConversationItem extends StatefulWidget { class _ConversationItemState extends State { final bloc; final Conversation conversation; - final bus = messageBloc; _ConversationItemState({@required this.conversation}) : bloc = ConversationMembersBloc(conversation.id); @@ -44,8 +43,11 @@ class _ConversationItemState extends State { elevation: 1, child: InkWell( onTap: () async { - await bus.publish( - {"state": "connect", "conversationId": conversation.id}); + await messageChannel.publish({ + "target": "home", + "state": "connect", + "conversationId": conversation.id + }); }, child: Container( padding: EdgeInsets.only( diff --git a/lib/src/ui/conversation_tab/widgets/home_view.dart b/lib/src/ui/conversation_tab/widgets/home_view.dart index 029ea61..6bb948e 100644 --- a/lib/src/ui/conversation_tab/widgets/home_view.dart +++ b/lib/src/ui/conversation_tab/widgets/home_view.dart @@ -4,6 +4,7 @@ import "../../../models/conversation_model.dart"; import "../../../blocs/conversation_bloc.dart"; import "../widgets/conversation_item.dart"; +import "../../widgets/top_bar.dart"; import "../../widgets/search_input.dart"; class HomeView extends StatefulWidget { @@ -30,22 +31,41 @@ class _HomeViewState extends State { @override Widget build(BuildContext context) { - return ListView(padding: EdgeInsets.only(top: 10.0), children: [ - Padding( - padding: EdgeInsets.only(left: 20.0, right: 20.0, bottom: 10.0), - child: SearchInput( - controller: searchController, - hintText: "Search for messages or users")), - 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()); - }) + return Column(children: [ + TopBar(title: "Conversations", children: [ + Padding( + padding: EdgeInsets.only(left: 13.0), + child: Text("Edit", + style: Theme.of(context) + .accentTextTheme + .title + .copyWith(fontWeight: FontWeight.w300))), + Spacer(), + IconButton( + icon: Icon(Icons.add_comment), + onPressed: () { + Navigator.pushNamed(context, "conversation/new"); + }), + ]), + Expanded( + child: + ListView(padding: EdgeInsets.only(top: 10.0), children: [ + Padding( + padding: EdgeInsets.only(left: 20.0, right: 20.0, bottom: 10.0), + child: SearchInput( + controller: searchController, + hintText: "Search for messages or users")), + 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()); + }) + ])) ]); } diff --git a/lib/src/ui/home.dart b/lib/src/ui/home.dart index 7b8f823..e044170 100644 --- a/lib/src/ui/home.dart +++ b/lib/src/ui/home.dart @@ -1,7 +1,6 @@ import "package:flutter/material.dart"; import 'dart:ui' as ui; -import "./widgets/top_bar.dart"; import "./conversation_tab/conversation_tab.dart"; import "./contact_tab/contact_tab.dart"; import "./bottom_bar/bottom_bar.dart"; @@ -37,7 +36,7 @@ class _HomeState extends State with SingleTickerProviderStateMixin { controller = TabController(vsync: this, length: 3); controller.index = 1; // Set default page to conversation page - messageBloc.bus.listen( + messageChannel.bus.listen( (Map data) async => await _processMessage(data)); } @@ -48,24 +47,26 @@ class _HomeState extends State with SingleTickerProviderStateMixin { } _processMessage(Map data) async { - if (data["state"] == "disconnect") { - // Disconnect and change state - await conversationManager.exit(); - setState(() { - currentConversationId = ""; - }); - } else if (data["state"] == "connect") { - // Connect and change state - await conversationManager.join(data["conversationId"]); - setState(() { - currentConversationId = data["conversationId"]; - }); - } else { - // show default - await conversationManager.exit(); - setState(() { - currentConversationId = ""; - }); + if (data["target"] == "home") { + if (data["state"] == "disconnect") { + // Disconnect and change state + await conversationManager.exit(); + setState(() { + currentConversationId = ""; + }); + } else if (data["state"] == "connect") { + // Connect and change state + await conversationManager.join(data["conversationId"]); + setState(() { + currentConversationId = data["conversationId"]; + }); + } else { + // show default + await conversationManager.exit(); + setState(() { + currentConversationId = ""; + }); + } } } @@ -73,18 +74,14 @@ class _HomeState extends State with SingleTickerProviderStateMixin { Widget build(BuildContext context) { return Scaffold( key: _scaffoldKey, - body: Column(children: [ - TopBar(state: _tabNumber), - Expanded( - child: TabBarView( - physics: NeverScrollableScrollPhysics(), - controller: controller, - children: [ - ContactTab(), - ConversationTab(), - Container(), - ])), - ]), + body: TabBarView( + physics: NeverScrollableScrollPhysics(), + controller: controller, + children: [ + ContactTab(), + ConversationTab(), + Container(), + ]), bottomNavigationBar: Column(mainAxisSize: MainAxisSize.min, children: [ BottomBar(conversationId: currentConversationId), diff --git a/lib/src/ui/widgets/top_bar.dart b/lib/src/ui/widgets/top_bar.dart index 212e497..5e57810 100644 --- a/lib/src/ui/widgets/top_bar.dart +++ b/lib/src/ui/widgets/top_bar.dart @@ -3,11 +3,11 @@ import "package:flutter/material.dart"; import "search_input.dart"; class TopBar extends StatelessWidget { - final int state; final String logo = "assets/logo.png"; - final List titleList = ["Contacts", "Conversations", "Settings"]; + final List children; + final String title; - TopBar({@required this.state}); + TopBar({@required this.children, @required this.title}); @override Widget build(BuildContext context) { @@ -19,41 +19,18 @@ class TopBar extends StatelessWidget { child: Container( padding: EdgeInsets.only(top: statusbarHeight, bottom: 0), child: Material( - type: MaterialType.transparency, - elevation: 0.0, - color: Colors.transparent, - child: Column(children: [ - Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Padding( - padding: EdgeInsets.only(left: 13.0), - child: Text("Edit", - style: Theme.of(context) - .accentTextTheme - .title - .copyWith(fontWeight: FontWeight.w300))), - Spacer(), - Text(titleList[state], - style: Theme.of(context).accentTextTheme.display1), - Spacer(), - (state == 1) - ? IconButton( - icon: Icon(Icons.add_comment), onPressed: () {}) - : Container(), - (state == 0) - ? IconButton(icon: Icon(Icons.add), onPressed: () {}) - : Container(), - (state == 2) - ? Opacity( - opacity: 0.0, - child: IconButton( - icon: Icon(Icons.edit), onPressed: () {})) - : Container(), - ], - ), - ])), + type: MaterialType.transparency, + elevation: 0.0, + color: Colors.transparent, + child: Stack(alignment: Alignment.center, children: [ + Text(title, style: Theme.of(context).accentTextTheme.display1), + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: children, + ) + ]), + ), decoration: BoxDecoration( gradient: LinearGradient( colors: [ From 08cf5a41b0613c120ee9e03f4d37c776e90bbc70 Mon Sep 17 00:00:00 2001 From: Sudharshan Date: Sat, 22 Jun 2019 17:07:50 +0800 Subject: [PATCH 15/24] feat: added new conversation page --- lib/src/ui/contact_tab/widgets/home_view.dart | 41 ++--- .../ui/conversation_tab/conversation_tab.dart | 4 +- .../conversation_tab/widgets/home_view.dart | 2 +- .../widgets/new_conversation_view.dart | 154 ++++++++++++++++++ .../widgets/contact_item.dart | 4 +- .../widgets/conversation_item.dart | 10 +- 6 files changed, 187 insertions(+), 28 deletions(-) create mode 100644 lib/src/ui/conversation_tab/widgets/new_conversation_view.dart rename lib/src/ui/{contact_tab => }/widgets/contact_item.dart (94%) rename lib/src/ui/{conversation_tab => }/widgets/conversation_item.dart (94%) diff --git a/lib/src/ui/contact_tab/widgets/home_view.dart b/lib/src/ui/contact_tab/widgets/home_view.dart index fe47449..755d23d 100644 --- a/lib/src/ui/contact_tab/widgets/home_view.dart +++ b/lib/src/ui/contact_tab/widgets/home_view.dart @@ -4,7 +4,7 @@ import 'package:sticky_headers/sticky_headers.dart'; import "../../../models/user_model.dart"; import "../../../blocs/contact_bloc.dart"; -import "../widgets/contact_item.dart"; +import "../../widgets/contact_item.dart"; import "../../widgets/top_bar.dart"; import "../../widgets/search_input.dart"; @@ -48,23 +48,6 @@ class _HomeViewState extends State { Navigator.pushNamed(context, "contact/new"); }), ]), - Padding( - padding: EdgeInsets.only(left: 15.0, right: 15.0, top: 10.0), - child: Column(mainAxisSize: MainAxisSize.min, children: [ - SearchInput( - controller: searchController, hintText: "Search for people"), - Padding( - padding: EdgeInsets.only(top: 10.0, bottom: 10.0), - child: Row(children: [ - Icon(Icons.people_outline, - color: Theme.of(context).primaryColorDark, size: 30.0), - Padding( - padding: EdgeInsets.only(left: 20.0), - child: Text("Invite Friends", - style: Theme.of(context).textTheme.title.copyWith( - color: Theme.of(context).primaryColorDark))), - ])), - ])), Expanded( child: StreamBuilder( stream: contactBloc.contacts, @@ -146,6 +129,26 @@ class _HomeViewState extends State { ]); }).toList(); - return ListView(padding: EdgeInsets.only(top: 0.0), children: children); + children.insertAll(0, [ + Padding( + padding: EdgeInsets.only(left: 15.0, right: 15.0), + child: Column(mainAxisSize: MainAxisSize.min, children: [ + SearchInput( + controller: searchController, hintText: "Search for people"), + Padding( + padding: EdgeInsets.only(top: 10.0, bottom: 10.0), + child: Row(children: [ + Icon(Icons.person_add, + color: Theme.of(context).primaryColorDark, size: 30.0), + Padding( + padding: EdgeInsets.only(left: 20.0), + child: Text("Invite Friends", + style: Theme.of(context).textTheme.title.copyWith( + color: Theme.of(context).primaryColorDark))), + ])), + ])), + ]); + + return ListView(padding: EdgeInsets.only(top: 10.0), children: children); } } diff --git a/lib/src/ui/conversation_tab/conversation_tab.dart b/lib/src/ui/conversation_tab/conversation_tab.dart index 854a5df..11ed6e6 100644 --- a/lib/src/ui/conversation_tab/conversation_tab.dart +++ b/lib/src/ui/conversation_tab/conversation_tab.dart @@ -1,5 +1,7 @@ import "package:flutter/material.dart"; + import "./widgets/home_view.dart"; +import "./widgets/new_conversation_view.dart"; class ConversationTab extends StatefulWidget { @override @@ -20,7 +22,7 @@ class _ConversationTabState extends State { builder = (BuildContext _) => HomeView(); break; case "conversation/new": - builder = (BuildContext _) => Center(child: Text("SOON")); + builder = (BuildContext _) => NewConversationView(); break; default: throw Exception("Invalid route: ${settings.name}"); diff --git a/lib/src/ui/conversation_tab/widgets/home_view.dart b/lib/src/ui/conversation_tab/widgets/home_view.dart index 6bb948e..649ac86 100644 --- a/lib/src/ui/conversation_tab/widgets/home_view.dart +++ b/lib/src/ui/conversation_tab/widgets/home_view.dart @@ -3,7 +3,7 @@ import "package:flutter/material.dart"; import "../../../models/conversation_model.dart"; import "../../../blocs/conversation_bloc.dart"; -import "../widgets/conversation_item.dart"; +import "../../widgets/conversation_item.dart"; import "../../widgets/top_bar.dart"; import "../../widgets/search_input.dart"; diff --git a/lib/src/ui/conversation_tab/widgets/new_conversation_view.dart b/lib/src/ui/conversation_tab/widgets/new_conversation_view.dart new file mode 100644 index 0000000..5083425 --- /dev/null +++ b/lib/src/ui/conversation_tab/widgets/new_conversation_view.dart @@ -0,0 +1,154 @@ +import "package:flutter/material.dart"; +import 'package:sticky_headers/sticky_headers.dart'; + +import "../../../models/user_model.dart"; +import "../../../blocs/contact_bloc.dart"; + +import "../../widgets/contact_item.dart"; +import "../../widgets/top_bar.dart"; +import "../../widgets/search_input.dart"; + +class NewConversationView extends StatefulWidget { + @override + State createState() { + return _NewConversationViewState(); + } +} + +class _NewConversationViewState extends State { + final searchController = TextEditingController(); + + @override + void initState() { + super.initState(); + contactBloc.fetchContacts(); + } + + @override + void dispose() { + searchController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Column(children: [ + TopBar(title: "New Conversation", children: [ + IconButton( + icon: Icon(Icons.arrow_back), + onPressed: () { + Navigator.pop(context); + }), + Spacer(), + Padding( + padding: EdgeInsets.only(right: 13.0), + child: Text("Next", + style: Theme.of(context) + .accentTextTheme + .title + .copyWith(fontWeight: FontWeight.w300))), + ]), + Expanded( + child: StreamBuilder( + stream: contactBloc.contacts, + builder: (context, AsyncSnapshot> snapshot) { + if (snapshot.hasData) { + return buildList(snapshot); + } else if (snapshot.hasError) { + return Text(snapshot.error.toString()); + } + return Center(child: CircularProgressIndicator()); + })) + ]); + } + + Widget buildList(AsyncSnapshot> snapshot) { + final Map> sortedList = { + "A": null, + "B": null, + "C": null, + "D": null, + "E": null, + "F": null, + "G": null, + "H": null, + "I": null, + "J": null, + "K": null, + "L": null, + "M": null, + "N": null, + "O": null, + "P": null, + "Q": null, + "R": null, + "S": null, + "T": null, + "U": null, + "V": null, + "W": null, + "X": null, + "Y": null, + "Z": null + }; + + // Sort the list into alphabets + sortedList.forEach((letter, list) { + sortedList[letter] = snapshot.data + .where((user) => user.firstName.startsWith(letter)) + .toList(); + }); + + // Create list of children + final children = sortedList.entries.map((entry) { + if (entry.value.length == 0) { + return Container(); + } + + return Column(mainAxisSize: MainAxisSize.min, children: [ + StickyHeader( + header: Container( + height: 21.0, + color: Colors.grey[200], + padding: EdgeInsets.symmetric(horizontal: 15.0), + alignment: Alignment.centerLeft, + child: Text(entry.key, + style: Theme.of(context) + .primaryTextTheme + .display1 + .copyWith(color: Theme.of(context).primaryColorDark)), + ), + content: ListView.builder( + physics: const NeverScrollableScrollPhysics(), + padding: EdgeInsets.only(top: 0.0), + shrinkWrap: true, + itemCount: entry.value.length, + itemBuilder: (context, index) { + return ContactItem(user: entry.value[index]); + })) + ]); + }).toList(); + + children.insertAll(0, [ + Padding( + padding: EdgeInsets.only(left: 15.0, right: 15.0), + child: Column(mainAxisSize: MainAxisSize.min, children: [ + SearchInput( + controller: searchController, hintText: "Search for people"), + Padding( + padding: EdgeInsets.only(top: 10.0, bottom: 10.0), + child: Row(children: [ + Icon(Icons.group_add, + color: Theme.of(context).primaryColorDark, size: 30.0), + Padding( + padding: EdgeInsets.only(left: 20.0), + child: Text("New Group", + style: Theme.of(context).textTheme.title.copyWith( + color: Theme.of(context).primaryColorDark))), + ])), + ])), + ]); + + return ListView(padding: EdgeInsets.only(top: 10.0), children: children); + } +} diff --git a/lib/src/ui/contact_tab/widgets/contact_item.dart b/lib/src/ui/widgets/contact_item.dart similarity index 94% rename from lib/src/ui/contact_tab/widgets/contact_item.dart rename to lib/src/ui/widgets/contact_item.dart index 7473225..a92f9dd 100644 --- a/lib/src/ui/contact_tab/widgets/contact_item.dart +++ b/lib/src/ui/widgets/contact_item.dart @@ -1,7 +1,7 @@ import "package:flutter/material.dart"; -import "../../../models/user_model.dart"; -import "../../widgets/user_avatar.dart"; +import "../../models/user_model.dart"; +import "../widgets/user_avatar.dart"; class ContactItem extends StatelessWidget { final User user; diff --git a/lib/src/ui/conversation_tab/widgets/conversation_item.dart b/lib/src/ui/widgets/conversation_item.dart similarity index 94% rename from lib/src/ui/conversation_tab/widgets/conversation_item.dart rename to lib/src/ui/widgets/conversation_item.dart index cff710e..32807ee 100644 --- a/lib/src/ui/conversation_tab/widgets/conversation_item.dart +++ b/lib/src/ui/widgets/conversation_item.dart @@ -1,11 +1,11 @@ import "package:flutter/material.dart"; -import "../../../models/user_model.dart"; -import "../../../models/conversation_model.dart"; -import "../../../blocs/conversation_bloc.dart"; -import "../../../blocs/message_bloc.dart"; +import "../../models/user_model.dart"; +import "../../models/conversation_model.dart"; +import "../../blocs/conversation_bloc.dart"; +import "../../blocs/message_bloc.dart"; -import "../../widgets/user_avatar.dart"; +import "../widgets/user_avatar.dart"; class ConversationItem extends StatefulWidget { final Conversation conversation; From b8292d550158bf7b06b6c4a8b203848cdcf41331 Mon Sep 17 00:00:00 2001 From: Sudharshan Date: Sat, 22 Jun 2019 17:21:04 +0800 Subject: [PATCH 16/24] feat: added photo picker functionality --- ios/Runner/Info.plist | 4 ++++ pubspec.yaml | 1 + 2 files changed, 5 insertions(+) diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 5d05155..892ed69 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -46,6 +46,10 @@ UIViewControllerBasedStatusBarAppearance + NSPhotoLibraryAddUsageDescription + Profile/Group picture + Privacy - Camera Usage Description + Selfie for profile/group picture NSMicrophoneUsageDescription $(PRODUCT_NAME) Microphone Usage! diff --git a/pubspec.yaml b/pubspec.yaml index 4d39eeb..3de864f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,6 +17,7 @@ dependencies: sqflite: ^1.1.0 eventsource: ^0.2.1 sticky_headers: ^0.1.7 + image_picker: ^0.6.0+10 dev_dependencies: flutter_test: From 56eaaad190c01627bb297ddfcd8d5d24bc0b692e Mon Sep 17 00:00:00 2001 From: Sudharshan Date: Sat, 22 Jun 2019 17:53:46 +0800 Subject: [PATCH 17/24] feat: adding stubs for the required views --- lib/src/ui/contact_tab/widgets/new_contact_view.dart | 0 lib/src/ui/conversation_tab/widgets/new_group_info_view.dart | 0 lib/src/ui/conversation_tab/widgets/new_group_view.dart | 0 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 lib/src/ui/contact_tab/widgets/new_contact_view.dart create mode 100644 lib/src/ui/conversation_tab/widgets/new_group_info_view.dart create mode 100644 lib/src/ui/conversation_tab/widgets/new_group_view.dart diff --git a/lib/src/ui/contact_tab/widgets/new_contact_view.dart b/lib/src/ui/contact_tab/widgets/new_contact_view.dart new file mode 100644 index 0000000..e69de29 diff --git a/lib/src/ui/conversation_tab/widgets/new_group_info_view.dart b/lib/src/ui/conversation_tab/widgets/new_group_info_view.dart new file mode 100644 index 0000000..e69de29 diff --git a/lib/src/ui/conversation_tab/widgets/new_group_view.dart b/lib/src/ui/conversation_tab/widgets/new_group_view.dart new file mode 100644 index 0000000..e69de29 From 6bc3b4ad858763dfcfc262a85600c039951ea3e8 Mon Sep 17 00:00:00 2001 From: Sudharshan Date: Sat, 22 Jun 2019 21:37:16 +0800 Subject: [PATCH 18/24] feat: adding selectable contacts --- ios/Runner.xcodeproj/project.pbxproj | 2 + lib/src/ui/contact_tab/widgets/home_view.dart | 13 ++- .../conversation_tab/widgets/home_view.dart | 13 ++- .../widgets/new_conversation_view.dart | 9 +- lib/src/ui/widgets/contact_item.dart | 96 +++++++++++++------ lib/src/ui/widgets/small_text_button.dart | 25 +++++ 6 files changed, 108 insertions(+), 50 deletions(-) create mode 100644 lib/src/ui/widgets/small_text_button.dart diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 4c77b9f..167d7e7 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -283,6 +283,7 @@ "${PODS_ROOT}/GoogleWebRTC/Frameworks/frameworks/WebRTC.framework", "${BUILT_PRODUCTS_DIR}/Just/Just.framework", "${BUILT_PRODUCTS_DIR}/PercentEncoder/PercentEncoder.framework", + "${BUILT_PRODUCTS_DIR}/image_picker/image_picker.framework", "${BUILT_PRODUCTS_DIR}/shared_preferences/shared_preferences.framework", "${BUILT_PRODUCTS_DIR}/sqflite/sqflite.framework", ); @@ -293,6 +294,7 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/WebRTC.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Just.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PercentEncoder.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_picker.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqflite.framework", ); diff --git a/lib/src/ui/contact_tab/widgets/home_view.dart b/lib/src/ui/contact_tab/widgets/home_view.dart index 755d23d..fce22d7 100644 --- a/lib/src/ui/contact_tab/widgets/home_view.dart +++ b/lib/src/ui/contact_tab/widgets/home_view.dart @@ -7,6 +7,7 @@ import "../../../blocs/contact_bloc.dart"; import "../../widgets/contact_item.dart"; import "../../widgets/top_bar.dart"; import "../../widgets/search_input.dart"; +import "../../widgets/small_text_button.dart"; class HomeView extends StatefulWidget { @override @@ -34,13 +35,11 @@ class _HomeViewState extends State { Widget build(BuildContext context) { return Column(children: [ TopBar(title: "Contacts", children: [ - Padding( - padding: EdgeInsets.only(left: 13.0), - child: Text("Edit", - style: Theme.of(context) - .accentTextTheme - .title - .copyWith(fontWeight: FontWeight.w300))), + SmallTextButton( + text: "Edit", + onClickCallback: () { + print("hello"); + }), Spacer(), IconButton( icon: Icon(Icons.add), diff --git a/lib/src/ui/conversation_tab/widgets/home_view.dart b/lib/src/ui/conversation_tab/widgets/home_view.dart index 649ac86..d2265ae 100644 --- a/lib/src/ui/conversation_tab/widgets/home_view.dart +++ b/lib/src/ui/conversation_tab/widgets/home_view.dart @@ -6,6 +6,7 @@ import "../../../blocs/conversation_bloc.dart"; import "../../widgets/conversation_item.dart"; import "../../widgets/top_bar.dart"; import "../../widgets/search_input.dart"; +import "../../widgets/small_text_button.dart"; class HomeView extends StatefulWidget { @override @@ -33,13 +34,11 @@ class _HomeViewState extends State { Widget build(BuildContext context) { return Column(children: [ TopBar(title: "Conversations", children: [ - Padding( - padding: EdgeInsets.only(left: 13.0), - child: Text("Edit", - style: Theme.of(context) - .accentTextTheme - .title - .copyWith(fontWeight: FontWeight.w300))), + SmallTextButton( + text: "Edit", + onClickCallback: () { + print("hello"); + }), Spacer(), IconButton( icon: Icon(Icons.add_comment), diff --git a/lib/src/ui/conversation_tab/widgets/new_conversation_view.dart b/lib/src/ui/conversation_tab/widgets/new_conversation_view.dart index 5083425..14b99e5 100644 --- a/lib/src/ui/conversation_tab/widgets/new_conversation_view.dart +++ b/lib/src/ui/conversation_tab/widgets/new_conversation_view.dart @@ -7,6 +7,7 @@ import "../../../blocs/contact_bloc.dart"; import "../../widgets/contact_item.dart"; import "../../widgets/top_bar.dart"; import "../../widgets/search_input.dart"; +import "../../widgets/small_text_button.dart"; class NewConversationView extends StatefulWidget { @override @@ -40,13 +41,7 @@ class _NewConversationViewState extends State { Navigator.pop(context); }), Spacer(), - Padding( - padding: EdgeInsets.only(right: 13.0), - child: Text("Next", - style: Theme.of(context) - .accentTextTheme - .title - .copyWith(fontWeight: FontWeight.w300))), + SmallTextButton(text: "Next", onClickCallback: () {}) ]), Expanded( child: StreamBuilder( diff --git a/lib/src/ui/widgets/contact_item.dart b/lib/src/ui/widgets/contact_item.dart index a92f9dd..4814f03 100644 --- a/lib/src/ui/widgets/contact_item.dart +++ b/lib/src/ui/widgets/contact_item.dart @@ -3,38 +3,76 @@ import "package:flutter/material.dart"; import "../../models/user_model.dart"; import "../widgets/user_avatar.dart"; -class ContactItem extends StatelessWidget { - final User user; +typedef void OnClickCallback(bool state); - ContactItem({@required this.user}); +class ContactItem extends StatefulWidget { + final User user; + final bool selectable; + final OnClickCallback onClickCallback; + + ContactItem( + {@required this.user, this.onClickCallback, this.selectable: false}); + + @override + State createState() { + return _ContactItemState(); + } +} + +class _ContactItemState extends State { + bool selected = false; @override Widget build(BuildContext context) { - return Container( - padding: EdgeInsets.only(top: 10.0, bottom: 10.0), - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - UserAvatar( - user: user, - radius: 18.0, - padding: EdgeInsets.only(left: 15.0)), - Padding( - padding: EdgeInsets.only(left: 15.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(user.firstName + " " + user.lastName, - style: Theme.of(context).textTheme.title, - overflow: TextOverflow.ellipsis), - Padding( - padding: EdgeInsets.only(top: 2), - child: Text("Last seen x ago", - style: Theme.of(context) - .textTheme - .subtitle - .copyWith(color: Color(0xFF455A64)))), - ])) - ])); + return Material( + type: MaterialType.transparency, + elevation: 1, + child: InkWell( + onTap: () async { + if (widget.selectable == true) { + setState(() { + selected = !selected; + }); + + widget.onClickCallback(selected); + } + }, + child: Container( + padding: EdgeInsets.only(top: 10.0, bottom: 10.0), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + (widget.selectable) + ? Checkbox( + value: selected, + activeColor: Theme.of(context).primaryColorDark, + onChanged: (state) {}) + : Container(), + UserAvatar( + user: widget.user, + radius: 18.0, + padding: EdgeInsets.only( + left: ((widget.selectable) ? 0 : 15.0))), + Padding( + padding: EdgeInsets.only(left: 15.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + widget.user.firstName + + " " + + widget.user.lastName, + style: Theme.of(context).textTheme.title, + overflow: TextOverflow.ellipsis), + Padding( + padding: EdgeInsets.only(top: 2), + child: Text("Last seen x ago", + style: Theme.of(context) + .textTheme + .subtitle + .copyWith( + color: Color(0xFF455A64)))), + ])) + ])))); } } diff --git a/lib/src/ui/widgets/small_text_button.dart b/lib/src/ui/widgets/small_text_button.dart new file mode 100644 index 0000000..48cee69 --- /dev/null +++ b/lib/src/ui/widgets/small_text_button.dart @@ -0,0 +1,25 @@ +import "package:flutter/material.dart"; + +typedef void OnClickCallback(); + +class SmallTextButton extends StatelessWidget { + final String text; + final OnClickCallback onClickCallback; + + SmallTextButton({@required this.text, @required this.onClickCallback}); + @override + Widget build(BuildContext context) { + return Material( + type: MaterialType.transparency, + elevation: 1, + child: Padding( + padding: EdgeInsets.all(10.0), + child: GestureDetector( + onTap: onClickCallback, + child: Text(text, + style: Theme.of(context) + .accentTextTheme + .title + .copyWith(fontWeight: FontWeight.w300))))); + } +} From b4849b7c2dfce46146054e6d9f0c2edc6ba86b49 Mon Sep 17 00:00:00 2001 From: Sudharshan Date: Sat, 22 Jun 2019 21:55:32 +0800 Subject: [PATCH 19/24] feat: added selectable contact support --- .../ui/conversation_tab/conversation_tab.dart | 4 + .../widgets/new_conversation_view.dart | 28 ++-- .../widgets/new_group_view.dart | 141 ++++++++++++++++++ 3 files changed, 161 insertions(+), 12 deletions(-) diff --git a/lib/src/ui/conversation_tab/conversation_tab.dart b/lib/src/ui/conversation_tab/conversation_tab.dart index 11ed6e6..fd31f7d 100644 --- a/lib/src/ui/conversation_tab/conversation_tab.dart +++ b/lib/src/ui/conversation_tab/conversation_tab.dart @@ -2,6 +2,7 @@ import "package:flutter/material.dart"; import "./widgets/home_view.dart"; import "./widgets/new_conversation_view.dart"; +import "./widgets/new_group_view.dart"; class ConversationTab extends StatefulWidget { @override @@ -24,6 +25,9 @@ class _ConversationTabState extends State { case "conversation/new": builder = (BuildContext _) => NewConversationView(); break; + case "conversation/group/new": + builder = (BuildContext _) => NewGroupView(); + break; default: throw Exception("Invalid route: ${settings.name}"); } diff --git a/lib/src/ui/conversation_tab/widgets/new_conversation_view.dart b/lib/src/ui/conversation_tab/widgets/new_conversation_view.dart index 14b99e5..edc3b97 100644 --- a/lib/src/ui/conversation_tab/widgets/new_conversation_view.dart +++ b/lib/src/ui/conversation_tab/widgets/new_conversation_view.dart @@ -41,7 +41,6 @@ class _NewConversationViewState extends State { Navigator.pop(context); }), Spacer(), - SmallTextButton(text: "Next", onClickCallback: () {}) ]), Expanded( child: StreamBuilder( @@ -130,17 +129,22 @@ class _NewConversationViewState extends State { child: Column(mainAxisSize: MainAxisSize.min, children: [ SearchInput( controller: searchController, hintText: "Search for people"), - Padding( - padding: EdgeInsets.only(top: 10.0, bottom: 10.0), - child: Row(children: [ - Icon(Icons.group_add, - color: Theme.of(context).primaryColorDark, size: 30.0), - Padding( - padding: EdgeInsets.only(left: 20.0), - child: Text("New Group", - style: Theme.of(context).textTheme.title.copyWith( - color: Theme.of(context).primaryColorDark))), - ])), + GestureDetector( + onTap: () { + Navigator.pushNamed(context, "conversation/group/new"); + }, + child: Padding( + padding: EdgeInsets.only(top: 10.0, bottom: 10.0), + child: Row(children: [ + Icon(Icons.group_add, + color: Theme.of(context).primaryColorDark, + size: 30.0), + Padding( + padding: EdgeInsets.only(left: 20.0), + child: Text("New Group", + style: Theme.of(context).textTheme.title.copyWith( + color: Theme.of(context).primaryColorDark))), + ]))), ])), ]); diff --git a/lib/src/ui/conversation_tab/widgets/new_group_view.dart b/lib/src/ui/conversation_tab/widgets/new_group_view.dart index e69de29..2d3a564 100644 --- a/lib/src/ui/conversation_tab/widgets/new_group_view.dart +++ b/lib/src/ui/conversation_tab/widgets/new_group_view.dart @@ -0,0 +1,141 @@ +import "package:flutter/material.dart"; +import 'package:sticky_headers/sticky_headers.dart'; + +import "../../../models/user_model.dart"; +import "../../../blocs/contact_bloc.dart"; + +import "../../widgets/contact_item.dart"; +import "../../widgets/top_bar.dart"; +import "../../widgets/search_input.dart"; +import "../../widgets/small_text_button.dart"; + +class NewGroupView extends StatefulWidget { + @override + State createState() { + return _NewGroupViewState(); + } +} + +class _NewGroupViewState extends State { + final searchController = TextEditingController(); + + @override + void initState() { + super.initState(); + contactBloc.fetchContacts(); + } + + @override + void dispose() { + searchController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Column(children: [ + TopBar(title: "New Group", children: [ + IconButton( + icon: Icon(Icons.arrow_back), + onPressed: () { + Navigator.pop(context); + }), + Spacer(), + SmallTextButton(text: "Next", onClickCallback: () {}) + ]), + Expanded( + child: StreamBuilder( + stream: contactBloc.contacts, + builder: (context, AsyncSnapshot> snapshot) { + if (snapshot.hasData) { + return buildList(snapshot); + } else if (snapshot.hasError) { + return Text(snapshot.error.toString()); + } + return Center(child: CircularProgressIndicator()); + })) + ]); + } + + Widget buildList(AsyncSnapshot> snapshot) { + final Map> sortedList = { + "A": null, + "B": null, + "C": null, + "D": null, + "E": null, + "F": null, + "G": null, + "H": null, + "I": null, + "J": null, + "K": null, + "L": null, + "M": null, + "N": null, + "O": null, + "P": null, + "Q": null, + "R": null, + "S": null, + "T": null, + "U": null, + "V": null, + "W": null, + "X": null, + "Y": null, + "Z": null + }; + + // Sort the list into alphabets + sortedList.forEach((letter, list) { + sortedList[letter] = snapshot.data + .where((user) => user.firstName.startsWith(letter)) + .toList(); + }); + + // Create list of children + final children = sortedList.entries.map((entry) { + if (entry.value.length == 0) { + return Container(); + } + + return Column(mainAxisSize: MainAxisSize.min, children: [ + StickyHeader( + header: Container( + height: 21.0, + color: Colors.grey[200], + padding: EdgeInsets.symmetric(horizontal: 15.0), + alignment: Alignment.centerLeft, + child: Text(entry.key, + style: Theme.of(context) + .primaryTextTheme + .display1 + .copyWith(color: Theme.of(context).primaryColorDark)), + ), + content: ListView.builder( + physics: const NeverScrollableScrollPhysics(), + padding: EdgeInsets.only(top: 0.0), + shrinkWrap: true, + itemCount: entry.value.length, + itemBuilder: (context, index) { + return ContactItem( + user: entry.value[index], + selectable: true, + onClickCallback: (state) {}); + })) + ]); + }).toList(); + + children.insertAll(0, [ + Padding( + padding: EdgeInsets.only(left: 15.0, right: 15.0), + child: Column(mainAxisSize: MainAxisSize.min, children: [ + SearchInput( + controller: searchController, hintText: "Search for people"), + ])), + ]); + + return ListView(padding: EdgeInsets.only(top: 10.0), children: children); + } +} From d00a4845411a509a79d774480692ace0e0ab7c86 Mon Sep 17 00:00:00 2001 From: Sudharshan Date: Wed, 26 Jun 2019 21:07:11 +0800 Subject: [PATCH 20/24] feat: implementing group info view --- .../ui/conversation_tab/conversation_tab.dart | 9 +- .../widgets/new_conversation_view.dart | 5 +- .../widgets/new_group_info_view.dart | 94 +++++++++++++++++++ .../widgets/new_group_view.dart | 13 ++- 4 files changed, 116 insertions(+), 5 deletions(-) diff --git a/lib/src/ui/conversation_tab/conversation_tab.dart b/lib/src/ui/conversation_tab/conversation_tab.dart index fd31f7d..c0b8eb8 100644 --- a/lib/src/ui/conversation_tab/conversation_tab.dart +++ b/lib/src/ui/conversation_tab/conversation_tab.dart @@ -3,6 +3,9 @@ import "package:flutter/material.dart"; import "./widgets/home_view.dart"; import "./widgets/new_conversation_view.dart"; import "./widgets/new_group_view.dart"; +import "./widgets/new_group_info_view.dart"; + +import "../../models/user_model.dart"; class ConversationTab extends StatefulWidget { @override @@ -25,9 +28,13 @@ class _ConversationTabState extends State { case "conversation/new": builder = (BuildContext _) => NewConversationView(); break; - case "conversation/group/new": + case "conversation/new/group": builder = (BuildContext _) => NewGroupView(); break; + case "conversation/new/groupinfo": + final List users = settings.arguments; + builder = (BuildContext _) => NewGroupInfoView(users: users); + break; default: throw Exception("Invalid route: ${settings.name}"); } diff --git a/lib/src/ui/conversation_tab/widgets/new_conversation_view.dart b/lib/src/ui/conversation_tab/widgets/new_conversation_view.dart index edc3b97..304b338 100644 --- a/lib/src/ui/conversation_tab/widgets/new_conversation_view.dart +++ b/lib/src/ui/conversation_tab/widgets/new_conversation_view.dart @@ -131,11 +131,12 @@ class _NewConversationViewState extends State { controller: searchController, hintText: "Search for people"), GestureDetector( onTap: () { - Navigator.pushNamed(context, "conversation/group/new"); + Navigator.pushNamed(context, "conversation/new/group"); }, child: Padding( padding: EdgeInsets.only(top: 10.0, bottom: 10.0), - child: Row(children: [ + child: + Row(mainAxisSize: MainAxisSize.max, children: [ Icon(Icons.group_add, color: Theme.of(context).primaryColorDark, size: 30.0), diff --git a/lib/src/ui/conversation_tab/widgets/new_group_info_view.dart b/lib/src/ui/conversation_tab/widgets/new_group_info_view.dart index e69de29..779fc9e 100644 --- a/lib/src/ui/conversation_tab/widgets/new_group_info_view.dart +++ b/lib/src/ui/conversation_tab/widgets/new_group_info_view.dart @@ -0,0 +1,94 @@ +import "package:flutter/material.dart"; + +import "../../../models/user_model.dart"; + +import "../../widgets/contact_item.dart"; +import "../../widgets/top_bar.dart"; +import "../../widgets/small_text_button.dart"; + +class NewGroupInfoView extends StatefulWidget { + final List users; + + NewGroupInfoView({@required this.users}); + + @override + State createState() { + return _NewGroupInfoViewState(); + } +} + +class _NewGroupInfoViewState extends State { + final descriptionController = TextEditingController(); + final nameController = TextEditingController(); + + @override + void dispose() { + descriptionController.dispose(); + nameController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Column(children: [ + TopBar(title: "New Group", children: [ + IconButton( + icon: Icon(Icons.arrow_back), + onPressed: () { + Navigator.pop(context); + }), + Spacer(), + SmallTextButton(text: "Create", onClickCallback: () {}) + ]), + Row(crossAxisAlignment: CrossAxisAlignment.center, children: [ + Container( + height: 70.0, + width: 70.0, + decoration: BoxDecoration( + color: Colors.grey, + borderRadius: BorderRadius.all(Radius.circular(35.0)))), + Flexible( + child: Column(mainAxisSize: MainAxisSize.min, children: [ + TextField( + controller: nameController, + autocorrect: false, + cursorWidth: 2.0, + cursorColor: Colors.grey[500], + style: Theme.of(context).textTheme.subtitle.copyWith( + color: Colors.grey[500], fontWeight: FontWeight.w300), + decoration: InputDecoration( + border: InputBorder.none, + filled: false, + hintText: "Enter group name", + hintStyle: Theme.of(context) + .textTheme + .subtitle + .copyWith(color: Colors.grey[500]))), + TextField( + controller: descriptionController, + autocorrect: false, + cursorWidth: 2.0, + cursorColor: Colors.grey[500], + style: Theme.of(context).textTheme.subtitle.copyWith( + color: Colors.grey[500], fontWeight: FontWeight.w300), + decoration: InputDecoration( + border: InputBorder.none, + filled: false, + hintText: "Enter group description", + hintStyle: Theme.of(context) + .textTheme + .subtitle + .copyWith(color: Colors.grey[500]))), + ])), + ]), + Expanded( + child: Padding( + padding: EdgeInsets.only(top: 20.0), + child: Column( + mainAxisSize: MainAxisSize.min, + children: widget.users + .map((user) => ContactItem(user: user)) + .toList()))) + ]); + } +} diff --git a/lib/src/ui/conversation_tab/widgets/new_group_view.dart b/lib/src/ui/conversation_tab/widgets/new_group_view.dart index 2d3a564..6068c51 100644 --- a/lib/src/ui/conversation_tab/widgets/new_group_view.dart +++ b/lib/src/ui/conversation_tab/widgets/new_group_view.dart @@ -19,6 +19,8 @@ class NewGroupView extends StatefulWidget { class _NewGroupViewState extends State { final searchController = TextEditingController(); + List selectedUsers = []; + @override void initState() { super.initState(); @@ -41,7 +43,12 @@ class _NewGroupViewState extends State { Navigator.pop(context); }), Spacer(), - SmallTextButton(text: "Next", onClickCallback: () {}) + SmallTextButton( + text: "Next", + onClickCallback: () { + Navigator.pushNamed(context, "conversation/new/groupinfo", + arguments: selectedUsers); + }) ]), Expanded( child: StreamBuilder( @@ -122,7 +129,9 @@ class _NewGroupViewState extends State { return ContactItem( user: entry.value[index], selectable: true, - onClickCallback: (state) {}); + onClickCallback: (state) { + selectedUsers.add(entry.value[index]); + }); })) ]); }).toList(); From acc2e8187d95ef4e87a67d9b0ef28374acf1a9a7 Mon Sep 17 00:00:00 2001 From: Sudharshan Date: Thu, 27 Jun 2019 10:06:07 +0800 Subject: [PATCH 21/24] feat: selecting --- lib/src/ui/contact_tab/widgets/home_view.dart | 54 ++++++++---------- .../conversation_tab/widgets/home_view.dart | 35 ++++++------ .../widgets/new_conversation_view.dart | 53 +++++++---------- .../widgets/new_group_view.dart | 57 ++++++++++++------- lib/src/ui/widgets/contact_item.dart | 8 ++- lib/src/ui/widgets/list_button.dart | 38 +++++++++++++ lib/src/ui/widgets/search_input.dart | 13 ++--- lib/src/ui/widgets/top_bar.dart | 26 ++++++--- lib/src/ui/widgets/user_avatar.dart | 1 - lib/src/ui/widgets/user_chip.dart | 18 ++++++ 10 files changed, 181 insertions(+), 122 deletions(-) create mode 100644 lib/src/ui/widgets/list_button.dart create mode 100644 lib/src/ui/widgets/user_chip.dart diff --git a/lib/src/ui/contact_tab/widgets/home_view.dart b/lib/src/ui/contact_tab/widgets/home_view.dart index fce22d7..e52d0a0 100644 --- a/lib/src/ui/contact_tab/widgets/home_view.dart +++ b/lib/src/ui/contact_tab/widgets/home_view.dart @@ -8,6 +8,7 @@ import "../../widgets/contact_item.dart"; import "../../widgets/top_bar.dart"; import "../../widgets/search_input.dart"; import "../../widgets/small_text_button.dart"; +import "../../widgets/list_button.dart"; class HomeView extends StatefulWidget { @override @@ -34,19 +35,23 @@ class _HomeViewState extends State { @override Widget build(BuildContext context) { return Column(children: [ - TopBar(title: "Contacts", children: [ - SmallTextButton( - text: "Edit", - onClickCallback: () { - print("hello"); - }), - Spacer(), - IconButton( - icon: Icon(Icons.add), - onPressed: () { - Navigator.pushNamed(context, "contact/new"); - }), - ]), + TopBar( + title: "Contacts", + search: SearchInput( + controller: searchController, hintText: "Search for people"), + children: [ + SmallTextButton( + text: "Edit", + onClickCallback: () { + print("hello"); + }), + Spacer(), + IconButton( + icon: Icon(Icons.add), + onPressed: () { + Navigator.pushNamed(context, "contact/new"); + }), + ]), Expanded( child: StreamBuilder( stream: contactBloc.contacts, @@ -129,25 +134,12 @@ class _HomeViewState extends State { }).toList(); children.insertAll(0, [ - Padding( - padding: EdgeInsets.only(left: 15.0, right: 15.0), - child: Column(mainAxisSize: MainAxisSize.min, children: [ - SearchInput( - controller: searchController, hintText: "Search for people"), - Padding( - padding: EdgeInsets.only(top: 10.0, bottom: 10.0), - child: Row(children: [ - Icon(Icons.person_add, - color: Theme.of(context).primaryColorDark, size: 30.0), - Padding( - padding: EdgeInsets.only(left: 20.0), - child: Text("Invite Friends", - style: Theme.of(context).textTheme.title.copyWith( - color: Theme.of(context).primaryColorDark))), - ])), - ])), + ListButton( + icon: Icons.people_outline, + text: "Invite Friends", + onClickCallback: () {}), ]); - return ListView(padding: EdgeInsets.only(top: 10.0), children: children); + return ListView(padding: EdgeInsets.only(top: 0.0), children: children); } } diff --git a/lib/src/ui/conversation_tab/widgets/home_view.dart b/lib/src/ui/conversation_tab/widgets/home_view.dart index d2265ae..bdc29af 100644 --- a/lib/src/ui/conversation_tab/widgets/home_view.dart +++ b/lib/src/ui/conversation_tab/widgets/home_view.dart @@ -33,27 +33,26 @@ class _HomeViewState extends State { @override Widget build(BuildContext context) { return Column(children: [ - TopBar(title: "Conversations", children: [ - SmallTextButton( - text: "Edit", - onClickCallback: () { - print("hello"); - }), - Spacer(), - IconButton( - icon: Icon(Icons.add_comment), - onPressed: () { - Navigator.pushNamed(context, "conversation/new"); - }), - ]), + TopBar( + title: "Conversations", + search: SearchInput( + controller: searchController, hintText: "Search for people"), + children: [ + SmallTextButton( + text: "Edit", + onClickCallback: () { + print("hello"); + }), + Spacer(), + IconButton( + icon: Icon(Icons.add_comment), + onPressed: () { + Navigator.pushNamed(context, "conversation/new"); + }), + ]), Expanded( child: ListView(padding: EdgeInsets.only(top: 10.0), children: [ - Padding( - padding: EdgeInsets.only(left: 20.0, right: 20.0, bottom: 10.0), - child: SearchInput( - controller: searchController, - hintText: "Search for messages or users")), StreamBuilder( stream: conversationsBloc.conversations, builder: (context, AsyncSnapshot> snapshot) { diff --git a/lib/src/ui/conversation_tab/widgets/new_conversation_view.dart b/lib/src/ui/conversation_tab/widgets/new_conversation_view.dart index 304b338..f7abb1f 100644 --- a/lib/src/ui/conversation_tab/widgets/new_conversation_view.dart +++ b/lib/src/ui/conversation_tab/widgets/new_conversation_view.dart @@ -7,7 +7,7 @@ import "../../../blocs/contact_bloc.dart"; import "../../widgets/contact_item.dart"; import "../../widgets/top_bar.dart"; import "../../widgets/search_input.dart"; -import "../../widgets/small_text_button.dart"; +import "../../widgets/list_button.dart"; class NewConversationView extends StatefulWidget { @override @@ -34,14 +34,18 @@ class _NewConversationViewState extends State { @override Widget build(BuildContext context) { return Column(children: [ - TopBar(title: "New Conversation", children: [ - IconButton( - icon: Icon(Icons.arrow_back), - onPressed: () { - Navigator.pop(context); - }), - Spacer(), - ]), + TopBar( + title: "New Conversation", + search: SearchInput( + controller: searchController, hintText: "Search for people"), + children: [ + IconButton( + icon: Icon(Icons.arrow_back), + onPressed: () { + Navigator.pop(context); + }), + Spacer(), + ]), Expanded( child: StreamBuilder( stream: contactBloc.contacts, @@ -124,31 +128,14 @@ class _NewConversationViewState extends State { }).toList(); children.insertAll(0, [ - Padding( - padding: EdgeInsets.only(left: 15.0, right: 15.0), - child: Column(mainAxisSize: MainAxisSize.min, children: [ - SearchInput( - controller: searchController, hintText: "Search for people"), - GestureDetector( - onTap: () { - Navigator.pushNamed(context, "conversation/new/group"); - }, - child: Padding( - padding: EdgeInsets.only(top: 10.0, bottom: 10.0), - child: - Row(mainAxisSize: MainAxisSize.max, children: [ - Icon(Icons.group_add, - color: Theme.of(context).primaryColorDark, - size: 30.0), - Padding( - padding: EdgeInsets.only(left: 20.0), - child: Text("New Group", - style: Theme.of(context).textTheme.title.copyWith( - color: Theme.of(context).primaryColorDark))), - ]))), - ])), + ListButton( + icon: Icons.group_add, + text: "New Group", + onClickCallback: () { + Navigator.pushNamed(context, "conversation/new/group"); + }), ]); - return ListView(padding: EdgeInsets.only(top: 10.0), children: children); + return ListView(padding: EdgeInsets.only(top: 0.0), children: children); } } diff --git a/lib/src/ui/conversation_tab/widgets/new_group_view.dart b/lib/src/ui/conversation_tab/widgets/new_group_view.dart index 6068c51..c74c627 100644 --- a/lib/src/ui/conversation_tab/widgets/new_group_view.dart +++ b/lib/src/ui/conversation_tab/widgets/new_group_view.dart @@ -8,6 +8,7 @@ import "../../widgets/contact_item.dart"; import "../../widgets/top_bar.dart"; import "../../widgets/search_input.dart"; import "../../widgets/small_text_button.dart"; +import "../../widgets/user_chip.dart"; class NewGroupView extends StatefulWidget { @override @@ -36,20 +37,25 @@ class _NewGroupViewState extends State { @override Widget build(BuildContext context) { return Column(children: [ - TopBar(title: "New Group", children: [ - IconButton( - icon: Icon(Icons.arrow_back), - onPressed: () { - Navigator.pop(context); - }), - Spacer(), - SmallTextButton( - text: "Next", - onClickCallback: () { - Navigator.pushNamed(context, "conversation/new/groupinfo", - arguments: selectedUsers); - }) - ]), + TopBar( + title: "New Group", + children: [ + IconButton( + icon: Icon(Icons.arrow_back), + onPressed: () { + Navigator.pop(context); + }), + Spacer(), + SmallTextButton( + text: "Next", + onClickCallback: () { + Navigator.pushNamed(context, "conversation/new/groupinfo", + arguments: selectedUsers); + }) + ], + search: SearchInput( + controller: searchController, hintText: "Search for people"), + ), Expanded( child: StreamBuilder( stream: contactBloc.contacts, @@ -129,8 +135,14 @@ class _NewGroupViewState extends State { return ContactItem( user: entry.value[index], selectable: true, - onClickCallback: (state) { - selectedUsers.add(entry.value[index]); + onClickCallback: (selected) { + setState(() { + if (selected) { + selectedUsers.add(entry.value[index]); + } else { + selectedUsers.remove(entry.value[index]); + } + }); }); })) ]); @@ -139,12 +151,13 @@ class _NewGroupViewState extends State { children.insertAll(0, [ Padding( padding: EdgeInsets.only(left: 15.0, right: 15.0), - child: Column(mainAxisSize: MainAxisSize.min, children: [ - SearchInput( - controller: searchController, hintText: "Search for people"), - ])), + child: Wrap( + spacing: 5.0, + runSpacing: 0.0, + children: + selectedUsers.map((user) => UserChip(user: user)).toList(), + )) ]); - - return ListView(padding: EdgeInsets.only(top: 10.0), children: children); + return ListView(padding: EdgeInsets.only(top: 0.0), children: children); } } diff --git a/lib/src/ui/widgets/contact_item.dart b/lib/src/ui/widgets/contact_item.dart index 4814f03..c73ac89 100644 --- a/lib/src/ui/widgets/contact_item.dart +++ b/lib/src/ui/widgets/contact_item.dart @@ -46,7 +46,13 @@ class _ContactItemState extends State { ? Checkbox( value: selected, activeColor: Theme.of(context).primaryColorDark, - onChanged: (state) {}) + onChanged: (state) { + setState(() { + selected = !selected; + }); + + widget.onClickCallback(selected); + }) : Container(), UserAvatar( user: widget.user, diff --git a/lib/src/ui/widgets/list_button.dart b/lib/src/ui/widgets/list_button.dart new file mode 100644 index 0000000..791c4ab --- /dev/null +++ b/lib/src/ui/widgets/list_button.dart @@ -0,0 +1,38 @@ +import "package:flutter/material.dart"; + +typedef void OnClickCallback(); + +class ListButton extends StatelessWidget { + final IconData icon; + final String text; + final OnClickCallback onClickCallback; + + ListButton( + {@required this.icon, + @required this.text, + @required this.onClickCallback}); + + @override + Widget build(BuildContext context) { + return Material( + type: MaterialType.transparency, + elevation: 1, + child: InkWell( + onTap: onClickCallback, + child: Container( + padding: EdgeInsets.only( + left: 15.0, right: 15.0, top: 12.0, bottom: 12.0), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Icon(icon, + size: 30.0, + color: Theme.of(context).primaryColorDark), + Padding( + padding: EdgeInsets.only(left: 20.0), + child: Text(text, + style: Theme.of(context).textTheme.title.copyWith( + color: Theme.of(context).primaryColorDark))), + ])))); + } +} diff --git a/lib/src/ui/widgets/search_input.dart b/lib/src/ui/widgets/search_input.dart index 4878d2c..0407174 100644 --- a/lib/src/ui/widgets/search_input.dart +++ b/lib/src/ui/widgets/search_input.dart @@ -16,16 +16,15 @@ class SearchInput extends StatelessWidget { children: [ Padding( padding: EdgeInsets.only(right: 5.0), - child: Icon(Icons.search, color: Colors.grey[500])), + child: Icon(Icons.search, color: Colors.white)), Flexible( child: TextField( controller: controller, autocorrect: false, - cursorWidth: 2.0, - cursorColor: Colors.grey[500], + cursorWidth: 3.0, + cursorColor: Colors.white, style: Theme.of(context).textTheme.subtitle.copyWith( - color: Colors.grey[500], - fontWeight: FontWeight.w300), + color: Colors.white, fontWeight: FontWeight.w300), decoration: InputDecoration( border: InputBorder.none, filled: false, @@ -33,10 +32,10 @@ class SearchInput extends StatelessWidget { hintStyle: Theme.of(context) .textTheme .subtitle - .copyWith(color: Colors.grey[500])))), + .copyWith(color: Colors.white)))), ])), decoration: BoxDecoration( - color: Colors.grey[200], + color: Colors.black.withOpacity(0.05), borderRadius: BorderRadius.all(Radius.circular(10.00)), )); } diff --git a/lib/src/ui/widgets/top_bar.dart b/lib/src/ui/widgets/top_bar.dart index 5e57810..cd42344 100644 --- a/lib/src/ui/widgets/top_bar.dart +++ b/lib/src/ui/widgets/top_bar.dart @@ -1,13 +1,13 @@ import "package:flutter/material.dart"; - import "search_input.dart"; class TopBar extends StatelessWidget { final String logo = "assets/logo.png"; + final SearchInput search; final List children; final String title; - TopBar({@required this.children, @required this.title}); + TopBar({@required this.children, @required this.title, this.search}); @override Widget build(BuildContext context) { @@ -22,13 +22,21 @@ class TopBar extends StatelessWidget { type: MaterialType.transparency, elevation: 0.0, color: Colors.transparent, - child: Stack(alignment: Alignment.center, children: [ - Text(title, style: Theme.of(context).accentTextTheme.display1), - Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, - children: children, - ) + child: Column(children: [ + Stack(alignment: Alignment.center, children: [ + Text(title, style: Theme.of(context).accentTextTheme.display1), + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: children, + ) + ]), + (search != null) + ? Padding( + padding: EdgeInsets.only( + left: 10.0, right: 10.0, bottom: 10.0), + child: search) + : Container(), ]), ), decoration: BoxDecoration( diff --git a/lib/src/ui/widgets/user_avatar.dart b/lib/src/ui/widgets/user_avatar.dart index e627041..f7f32bb 100644 --- a/lib/src/ui/widgets/user_avatar.dart +++ b/lib/src/ui/widgets/user_avatar.dart @@ -1,5 +1,4 @@ import "package:flutter/material.dart"; -import 'dart:ui' as ui; import "dart:async"; import "../../models/user_model.dart"; diff --git a/lib/src/ui/widgets/user_chip.dart b/lib/src/ui/widgets/user_chip.dart new file mode 100644 index 0000000..4b5d371 --- /dev/null +++ b/lib/src/ui/widgets/user_chip.dart @@ -0,0 +1,18 @@ +import "package:flutter/material.dart"; + +import "../../models/user_model.dart"; +import "./user_avatar.dart"; + +class UserChip extends StatelessWidget { + final User user; + + UserChip({@required this.user}); + + @override + Widget build(BuildContext context) { + return Chip( + avatar: UserAvatar(user: user, radius: 12.0), + elevation: 1.5, + label: Text(user.firstName + " " + user.lastName)); + } +} From c8cdbd34e90cc8f1efdd863ddea7a32f212c38c8 Mon Sep 17 00:00:00 2001 From: Sudharshan Date: Sat, 29 Jun 2019 10:52:00 +0800 Subject: [PATCH 22/24] feat: added group create and profile picture picker --- ios/Runner.xcodeproj/project.pbxproj | 4 +- ios/Runner/Info.plist | 4 +- .../widgets/new_group_info_view.dart | 126 ++++++++++++------ .../widgets/new_group_view.dart | 8 +- pubspec.yaml | 2 +- 5 files changed, 95 insertions(+), 49 deletions(-) diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 167d7e7..bf58000 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -283,7 +283,7 @@ "${PODS_ROOT}/GoogleWebRTC/Frameworks/frameworks/WebRTC.framework", "${BUILT_PRODUCTS_DIR}/Just/Just.framework", "${BUILT_PRODUCTS_DIR}/PercentEncoder/PercentEncoder.framework", - "${BUILT_PRODUCTS_DIR}/image_picker/image_picker.framework", + "${BUILT_PRODUCTS_DIR}/image_picker_modern/image_picker_modern.framework", "${BUILT_PRODUCTS_DIR}/shared_preferences/shared_preferences.framework", "${BUILT_PRODUCTS_DIR}/sqflite/sqflite.framework", ); @@ -294,7 +294,7 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/WebRTC.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Just.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PercentEncoder.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_picker.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_picker_modern.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqflite.framework", ); diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 892ed69..a9600aa 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -46,9 +46,9 @@ UIViewControllerBasedStatusBarAppearance - NSPhotoLibraryAddUsageDescription + NSPhotoLibraryUsageDescription Profile/Group picture - Privacy - Camera Usage Description + NSCameraUsageDescription Selfie for profile/group picture NSMicrophoneUsageDescription $(PRODUCT_NAME) Microphone Usage! diff --git a/lib/src/ui/conversation_tab/widgets/new_group_info_view.dart b/lib/src/ui/conversation_tab/widgets/new_group_info_view.dart index 779fc9e..21d15c6 100644 --- a/lib/src/ui/conversation_tab/widgets/new_group_info_view.dart +++ b/lib/src/ui/conversation_tab/widgets/new_group_info_view.dart @@ -1,10 +1,13 @@ import "package:flutter/material.dart"; +import 'package:image_picker_modern/image_picker_modern.dart'; +import "dart:io"; import "../../../models/user_model.dart"; import "../../widgets/contact_item.dart"; import "../../widgets/top_bar.dart"; import "../../widgets/small_text_button.dart"; +import "../../widgets/list_button.dart"; class NewGroupInfoView extends StatefulWidget { final List users; @@ -21,6 +24,8 @@ class _NewGroupInfoViewState extends State { final descriptionController = TextEditingController(); final nameController = TextEditingController(); + File _image; + @override void dispose() { descriptionController.dispose(); @@ -40,50 +45,87 @@ class _NewGroupInfoViewState extends State { Spacer(), SmallTextButton(text: "Create", onClickCallback: () {}) ]), - Row(crossAxisAlignment: CrossAxisAlignment.center, children: [ - Container( - height: 70.0, - width: 70.0, - decoration: BoxDecoration( - color: Colors.grey, - borderRadius: BorderRadius.all(Radius.circular(35.0)))), - Flexible( - child: Column(mainAxisSize: MainAxisSize.min, children: [ - TextField( - controller: nameController, - autocorrect: false, - cursorWidth: 2.0, - cursorColor: Colors.grey[500], - style: Theme.of(context).textTheme.subtitle.copyWith( - color: Colors.grey[500], fontWeight: FontWeight.w300), - decoration: InputDecoration( - border: InputBorder.none, - filled: false, - hintText: "Enter group name", - hintStyle: Theme.of(context) - .textTheme - .subtitle - .copyWith(color: Colors.grey[500]))), - TextField( - controller: descriptionController, - autocorrect: false, - cursorWidth: 2.0, - cursorColor: Colors.grey[500], - style: Theme.of(context).textTheme.subtitle.copyWith( - color: Colors.grey[500], fontWeight: FontWeight.w300), - decoration: InputDecoration( - border: InputBorder.none, - filled: false, - hintText: "Enter group description", - hintStyle: Theme.of(context) - .textTheme - .subtitle - .copyWith(color: Colors.grey[500]))), - ])), - ]), + Padding( + padding: EdgeInsets.only(left: 15.0, right: 15.0, top: 10.0), + child: Row(crossAxisAlignment: CrossAxisAlignment.center, children: < + Widget>[ + Container( + height: 100.0, + width: 100.0, + decoration: (_image == null) + ? (BoxDecoration( + color: Colors.grey, + borderRadius: BorderRadius.all(Radius.circular(50.0)))) + : BoxDecoration( + image: DecorationImage( + image: FileImage(_image), + fit: BoxFit.cover, + ))), + Flexible( + child: + Column(mainAxisSize: MainAxisSize.min, children: [ + Container( + margin: EdgeInsets.only(left: 8.0), + padding: EdgeInsets.only(left: 10.0, right: 10.0), + color: Colors.grey[100], + child: TextField( + controller: nameController, + autocorrect: false, + cursorWidth: 2.0, + cursorColor: Colors.grey[500], + style: Theme.of(context).textTheme.subtitle.copyWith( + color: Colors.grey[500], fontWeight: FontWeight.w300), + decoration: InputDecoration( + border: InputBorder.none, + filled: false, + hintText: "Enter group name", + hintStyle: Theme.of(context) + .textTheme + .subtitle + .copyWith(color: Colors.grey[500])))), + Container( + margin: EdgeInsets.only(left: 8.0, top: 5.0), + padding: EdgeInsets.only(left: 10.0, right: 10.0), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(5.0), + color: Colors.grey[100], + ), + child: TextField( + controller: descriptionController, + autocorrect: false, + maxLines: 3, + cursorWidth: 2.0, + cursorColor: Colors.grey[500], + style: Theme.of(context).textTheme.subtitle.copyWith( + color: Colors.grey[500], + fontWeight: FontWeight.w300, + ), + decoration: InputDecoration( + border: InputBorder.none, + filled: false, + hintText: "Enter group description", + hintStyle: Theme.of(context) + .textTheme + .subtitle + .copyWith(color: Colors.grey[500])))), + ])), + ])), + Padding( + padding: EdgeInsets.only(top: 10.0), + child: ListButton( + icon: Icons.insert_photo, + text: "Add a group photo", + onClickCallback: () async { + var image = + await ImagePicker.pickImage(source: ImageSource.camera); + + setState(() { + _image = image; + }); + })), Expanded( child: Padding( - padding: EdgeInsets.only(top: 20.0), + padding: EdgeInsets.only(top: 0.0), child: Column( mainAxisSize: MainAxisSize.min, children: widget.users diff --git a/lib/src/ui/conversation_tab/widgets/new_group_view.dart b/lib/src/ui/conversation_tab/widgets/new_group_view.dart index c74c627..0c3119e 100644 --- a/lib/src/ui/conversation_tab/widgets/new_group_view.dart +++ b/lib/src/ui/conversation_tab/widgets/new_group_view.dart @@ -49,8 +49,12 @@ class _NewGroupViewState extends State { SmallTextButton( text: "Next", onClickCallback: () { - Navigator.pushNamed(context, "conversation/new/groupinfo", - arguments: selectedUsers); + if (selectedUsers.length <= 1) { + return; + } else { + Navigator.pushNamed(context, "conversation/new/groupinfo", + arguments: selectedUsers); + } }) ], search: SearchInput( diff --git a/pubspec.yaml b/pubspec.yaml index 3de864f..e6b8ebd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,7 +17,7 @@ dependencies: sqflite: ^1.1.0 eventsource: ^0.2.1 sticky_headers: ^0.1.7 - image_picker: ^0.6.0+10 + image_picker_modern: ^0.4.12+2 dev_dependencies: flutter_test: From 7ec27474ff1b4f261cbc3f17b9b59ebea1513697 Mon Sep 17 00:00:00 2001 From: Sudharshan Date: Sat, 29 Jun 2019 11:57:34 +0800 Subject: [PATCH 23/24] feat: tested and working image picker --- .../widgets/new_group_info_view.dart | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/lib/src/ui/conversation_tab/widgets/new_group_info_view.dart b/lib/src/ui/conversation_tab/widgets/new_group_info_view.dart index 21d15c6..eab65bd 100644 --- a/lib/src/ui/conversation_tab/widgets/new_group_info_view.dart +++ b/lib/src/ui/conversation_tab/widgets/new_group_info_view.dart @@ -49,18 +49,9 @@ class _NewGroupInfoViewState extends State { padding: EdgeInsets.only(left: 15.0, right: 15.0, top: 10.0), child: Row(crossAxisAlignment: CrossAxisAlignment.center, children: < Widget>[ - Container( - height: 100.0, - width: 100.0, - decoration: (_image == null) - ? (BoxDecoration( - color: Colors.grey, - borderRadius: BorderRadius.all(Radius.circular(50.0)))) - : BoxDecoration( - image: DecorationImage( - image: FileImage(_image), - fit: BoxFit.cover, - ))), + (_image != null) + ? CircleAvatar(radius: 50, backgroundImage: FileImage(_image)) + : CircleAvatar(radius: 50, backgroundColor: Colors.grey[300]), Flexible( child: Column(mainAxisSize: MainAxisSize.min, children: [ @@ -117,7 +108,7 @@ class _NewGroupInfoViewState extends State { text: "Add a group photo", onClickCallback: () async { var image = - await ImagePicker.pickImage(source: ImageSource.camera); + await ImagePicker.pickImage(source: ImageSource.gallery); setState(() { _image = image; From 366b329ce858bebf4ae19bdcdc363f8b9a364e9d Mon Sep 17 00:00:00 2001 From: Sudharshan Date: Sat, 29 Jun 2019 14:56:35 +0800 Subject: [PATCH 24/24] feat: logic for new group creation --- lib/src/resources/conversation_api_provider.dart | 11 +++++++++++ .../widgets/new_group_info_view.dart | 14 +++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/lib/src/resources/conversation_api_provider.dart b/lib/src/resources/conversation_api_provider.dart index 1d95a48..df0c00a 100644 --- a/lib/src/resources/conversation_api_provider.dart +++ b/lib/src/resources/conversation_api_provider.dart @@ -65,6 +65,17 @@ class ConversationApiProvider { } } + Future createConversationMember( + String conversationId, String userId) async { + final jwt = await loginManager.getToken(); + await http.post("$baseUrlCore/user/conversation/$conversationId/member", + headers: { + HttpHeaders.contentTypeHeader: "application/json", + HttpHeaders.authorizationHeader: "Bearer $jwt" + }, + body: jsonEncode({"id": userId})); + } + Future> fetchConversationMembers(String id) async { final jwt = await loginManager.getToken(); try { diff --git a/lib/src/ui/conversation_tab/widgets/new_group_info_view.dart b/lib/src/ui/conversation_tab/widgets/new_group_info_view.dart index eab65bd..bbe99af 100644 --- a/lib/src/ui/conversation_tab/widgets/new_group_info_view.dart +++ b/lib/src/ui/conversation_tab/widgets/new_group_info_view.dart @@ -4,6 +4,8 @@ import "dart:io"; import "../../../models/user_model.dart"; +import "../../../resources/conversation_api_provider.dart"; + import "../../widgets/contact_item.dart"; import "../../widgets/top_bar.dart"; import "../../widgets/small_text_button.dart"; @@ -23,6 +25,7 @@ class NewGroupInfoView extends StatefulWidget { class _NewGroupInfoViewState extends State { final descriptionController = TextEditingController(); final nameController = TextEditingController(); + final conversationApiProvider = ConversationApiProvider(); File _image; @@ -43,7 +46,16 @@ class _NewGroupInfoViewState extends State { Navigator.pop(context); }), Spacer(), - SmallTextButton(text: "Create", onClickCallback: () {}) + SmallTextButton( + text: "Create", + onClickCallback: () async { + final conversation = await conversationApiProvider + .createConversation(nameController.text); + + widget.users.forEach((user) async => await conversationApiProvider + .createConversationMember(conversation.id, user.id)); + Navigator.pushNamed(context, "conversation/home"); + }) ]), Padding( padding: EdgeInsets.only(left: 15.0, right: 15.0, top: 10.0),