From 040eedc3a3c53ce1c01d7b7fb0beef92819d93ff Mon Sep 17 00:00:00 2001 From: David-solly Date: Mon, 2 Mar 2020 20:50:33 +0000 Subject: [PATCH 01/10] Initial commit --- pubspec.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.lock b/pubspec.lock index 49189c0..09be7ec 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -300,7 +300,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.11" + version: "0.2.14" typed_data: dependency: transitive description: From 29578d6b11bd3cf6247c616673320fd2681666a7 Mon Sep 17 00:00:00 2001 From: David-solly Date: Mon, 2 Mar 2020 22:20:25 +0000 Subject: [PATCH 02/10] Added app navigation --- lib/screens/app_base_screen.dart | 160 ++++++++++ lib/screens/authentication_service.dart | 5 +- lib/screens/fragments/chat_fragment.dart | 113 ++++++++ .../navigation_drawers/navigation_drawer.dart | 274 ++++++++++++++++++ .../fragments/templates/destination_view.dart | 177 +++++++++++ lib/screens/home_page.dart | 2 +- lib/styles/constants.dart | 5 + pubspec.lock | 63 ++++ pubspec.yaml | 11 +- 9 files changed, 801 insertions(+), 9 deletions(-) create mode 100644 lib/screens/app_base_screen.dart create mode 100644 lib/screens/fragments/chat_fragment.dart create mode 100644 lib/screens/fragments/navigation_drawers/navigation_drawer.dart create mode 100644 lib/screens/fragments/templates/destination_view.dart create mode 100644 lib/styles/constants.dart diff --git a/lib/screens/app_base_screen.dart b/lib/screens/app_base_screen.dart new file mode 100644 index 0000000..5c7db43 --- /dev/null +++ b/lib/screens/app_base_screen.dart @@ -0,0 +1,160 @@ +import 'package:digamobile/screens/fragments/navigation_drawers/navigation_drawer.dart'; +import 'package:digamobile/screens/fragments/templates/destination_view.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_inner_drawer/inner_drawer.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:line_awesome_icons/line_awesome_icons.dart'; + +import 'home_page.dart'; + +class AppBase extends StatefulWidget { + AppBase({Key key}) : super(key: key); + + @override + _AppBaseState createState() => _AppBaseState(); +} + +class _AppBaseState extends State with TickerProviderStateMixin { + final GlobalKey _innerDrawerKey = + GlobalKey(); + + bool _onTapToClose = false; + bool _swipe = true; + bool _tapScaffold = true; + InnerDrawerAnimation _animationType = InnerDrawerAnimation.static; + double _offset = 0.4; + + double _dragUpdate = 0; + int _index = 0; + InnerDrawerDirection _direction = InnerDrawerDirection.start; + + Color pickerColor = Color(0xff443a49); + Color currentColor = Colors.black54; + ValueChanged onColorChanged; + +//navigation state + List _faders; + List _destinationKeys; + + // Custom navigator takes a global key if you want to access the + // navigator from outside it's widget tree subtree + GlobalKey navigatorKey = GlobalKey(); + + @override + void initState() { + print("@@@@----MAIN____APPP____INIT___STATE"); + + _faders = + allDestinations.map((PageDestination destination) { + return AnimationController( + vsync: this, duration: Duration(milliseconds: 500)); + }).toList(); + _faders[_index].value = 1.0; + _destinationKeys = + List.generate(allDestinations.length, (int index) => GlobalKey()) + .toList(); + + super.initState(); + } + + @override + void dispose() { + for (AnimationController controller in _faders) controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: InnerDrawer( + key: _innerDrawerKey, + onTapClose: _onTapToClose, + tapScaffoldEnabled: _tapScaffold, + + offset: IDOffset.horizontal(_offset), + swipe: !_swipe, + boxShadow: _direction == InnerDrawerDirection.start && + _animationType == InnerDrawerAnimation.linear + ? [] + : null, + colorTransition: currentColor, + leftAnimationType: _animationType, + rightAnimationType: InnerDrawerAnimation.linear, + leftChild: NavigationDrawer(dragUpdate: _dragUpdate), + + //rightChild: MapFilterDrawer(), + + onDragUpdate: (double val, InnerDrawerDirection direction) { + _direction = direction; + setState(() => _dragUpdate = val); + }, + //innerDrawerCallback: (a) => print(a), + scaffold: Scaffold( + floatingActionButton: FloatingActionButton.extended( + onPressed: () {}, + label: Padding( + padding: const EdgeInsets.only(left: 8.0), + child: Text("Chat Assist"), + ), + icon: Icon( + Icons.chat, + color: allDestinations[_index].materialColorLight, + ), + ), + floatingActionButtonLocation: + FloatingActionButtonLocation.centerDocked, + extendBody: false, + bottomNavigationBar: BottomNavigationBar( + //type: BottomNavigationBarType.fixed, + selectedIconTheme: IconThemeData(size: 26), + selectedItemColor: allDestinations[_index].materialColor, + unselectedItemColor: Colors.grey.shade900, + showUnselectedLabels: true, + onTap: (index) { + // navigatorKey.currentState.maybePop(); + setState(() => _index = index); + }, + currentIndex: _index, + items: allDestinations + .map((pageDestination) { + return BottomNavigationBarItem( + icon: Icon(pageDestination.icon), + activeIcon: Icon(pageDestination.activeIcon), + backgroundColor: pageDestination.materialColor, + title: Text(pageDestination.title)); + }).toList(), + ), + body: Stack( + fit: StackFit.expand, + children: allDestinations.map((PageDestination destination) { + final Widget view = FadeTransition( + opacity: _faders[destination.index] + .drive(CurveTween(curve: Curves.fastOutSlowIn)), + child: KeyedSubtree( + key: _destinationKeys[destination.index], + child: _index == 0 + ? HomePage( + "Welcome", + ) + : DestinationView( + destination: destination, + ), + ), + ); + if (destination.index == _index) { + _faders[destination.index].forward(); + return view; + } else { + _faders[destination.index].reverse(); + if (_faders[destination.index].isAnimating) { + return IgnorePointer(child: view); + } + return Offstage(child: view); + } + }).toList(), + )), + ), + ); + } +} diff --git a/lib/screens/authentication_service.dart b/lib/screens/authentication_service.dart index f5fc8ae..f43a254 100644 --- a/lib/screens/authentication_service.dart +++ b/lib/screens/authentication_service.dart @@ -1,4 +1,5 @@ import 'package:digamobile/login_screen.dart'; +import 'package:digamobile/screens/app_base_screen.dart'; import 'package:digamobile/screens/home_page.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; @@ -17,7 +18,7 @@ class AuthenticationService extends StatelessWidget { stream: FirebaseAuth.instance.onAuthStateChanged, builder: (context, snapshot) { if (snapshot.hasData) { - return HomePage(title); + return AppBase(); } else { return LoginScreen(); } @@ -26,4 +27,4 @@ class AuthenticationService extends StatelessWidget { ), ); } -} \ No newline at end of file +} diff --git a/lib/screens/fragments/chat_fragment.dart b/lib/screens/fragments/chat_fragment.dart new file mode 100644 index 0000000..44a534b --- /dev/null +++ b/lib/screens/fragments/chat_fragment.dart @@ -0,0 +1,113 @@ +import 'dart:async'; + +import 'package:dash_chat/dash_chat.dart'; +import 'package:flutter/cupertino.dart'; + +class ChatFragment extends StatefulWidget { + @override + _ChatFragmentState createState() => _ChatFragmentState(); +} + +class _ChatFragmentState extends State { + final GlobalKey _chatViewKey = GlobalKey(); + + final ChatUser user = ChatUser( + name: "Fayeed", + uid: "123456789", + avatar: "https://www.wrappixel.com/ampleadmin/assets/images/users/4.jpg", + ); + + final ChatUser otherUser = ChatUser( + name: "Mrfatty", + uid: "25649654", + ); + + List messages = List(); + + var m = List(); + + var i = 0; + + @override + void initState() { + super.initState(); + + messages.addAll([ + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ]); + } + + void systemMessage() { + Timer(Duration(milliseconds: 300), () { + if (i < 6) { + setState(() { + messages = [...messages, m[i]]; + }); + i++; + } + Timer(Duration(milliseconds: 300), () { + _chatViewKey.currentState.scrollController + ..animateTo( + _chatViewKey.currentState.scrollController.position.maxScrollExtent, + curve: Curves.easeOut, + duration: const Duration(milliseconds: 300), + ); + }); + }); + } + + void onSend(ChatMessage message) { + print(message.toJson()); + // var documentReference = Firestore.instance + // .collection('messages') + // .document(DateTime.now().millisecondsSinceEpoch.toString()); + + // Firestore.instance.runTransaction((transaction) async { + // await transaction.set( + // documentReference, + // message.toJson(), + // ); + // }); + setState(() { + messages = [...messages, message]; + print(messages.length); + }); + + if (i == 0) { + systemMessage(); + Timer(Duration(milliseconds: 600), () { + systemMessage(); + }); + } else { + systemMessage(); + } + } + + @override + Widget build(BuildContext context) { + // TODO: implement build + throw UnimplementedError(); + } +} diff --git a/lib/screens/fragments/navigation_drawers/navigation_drawer.dart b/lib/screens/fragments/navigation_drawers/navigation_drawer.dart new file mode 100644 index 0000000..dea4163 --- /dev/null +++ b/lib/screens/fragments/navigation_drawers/navigation_drawer.dart @@ -0,0 +1,274 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:line_awesome_icons/line_awesome_icons.dart'; + +import '../../../auth_service.dart'; + +class NavigationDrawer extends StatelessWidget { + NavigationDrawer({Key key, this.dragUpdate: 0}) : super(key: key); + final double dragUpdate; + final availableSos = false; + final isSignedIn = false; + final hasRated = false; + @override + Widget build(BuildContext context) { + return Container( + child: Material( + child: Stack( + children: [ + Container( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topRight, + end: Alignment.bottomLeft, + // Add one stop for each color. Stops should increase from 0 to 1 + //stops: [0.1, 0.5,0.5, 0.7, 0.9], + colors: [ + ColorTween( + begin: Colors.blueAccent, + end: Colors.blueGrey[400].withRed(100), + ).lerp(dragUpdate), + ColorTween( + begin: Colors.green, + end: Colors.blueGrey[800].withGreen(80), + ).lerp(dragUpdate), + ], + ), + ), + child: Stack( + fit: StackFit.expand, + children: [ + Padding( + padding: EdgeInsets.only(left: 30), + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Column( + children: [ + Container( + margin: EdgeInsets.only( + left: 10, bottom: 15, top: 72), + width: 80, + child: ClipRRect( + child: Container( + height: 90, + width: 90, + color: Colors.blueAccent, + ), + borderRadius: BorderRadius.circular(50), + ), + ), + Text( + "User", + style: + TextStyle(color: Colors.white, fontSize: 18), + ) + ], + //mainAxisAlignment: MainAxisAlignment.center, + ), + Padding( + padding: EdgeInsets.all(10), + ), + Material( + color: Colors.transparent, + child: InkWell( + onTap: () => print("Rate us"), + child: ListTile( + title: Text( + "Rate", + style: TextStyle( + color: Colors.white, fontSize: 14), + ), + leading: Icon( + hasRated + ? LineAwesomeIcons.star + : LineAwesomeIcons.star_o, + color: Colors.white, + size: 22, + ))), + ), + Padding( + padding: const EdgeInsets.only(bottom: 24.0), + child: Container( + height: 1, + color: Colors.grey, + ), + ), + Material( + color: availableSos + ? Colors.red[800] + : Colors.red.shade900.withAlpha(150), + child: InkWell( + onTap: () => print("Sos"), + child: ListTile( + title: Text( + "S.O.S", + style: TextStyle( + color: availableSos + ? Colors.white + : Colors.grey.shade300, + fontSize: 14), + ), + trailing: availableSos + ? Icon( + Icons.adjust, + color: Colors.green[300], + ) + : Icon( + Icons.album, + color: Colors.red[700].withAlpha(150), + ), + leading: Icon( + LineAwesomeIcons.exclamation_triangle, + //FontAwesomeIcons.exclamationTriangle, + color: Colors.white, + size: 22, + ))), + ), + Padding( + padding: const EdgeInsets.only(top: 24.0), + child: Container( + height: 1, + color: Colors.grey, + ), + ), + Material( + color: Colors.transparent, + child: InkWell( + onTap: () => print("My Account"), + child: ListTile( + title: Text( + "My Account", + style: TextStyle( + color: Colors.white, fontSize: 14), + ), + leading: Icon( + LineAwesomeIcons.lock, + color: Colors.white, + size: 22, + ))), + ), + Material( + color: Colors.transparent, + child: InkWell( + onTap: () => print("Settings"), + child: ListTile( + title: Text( + "Settings", + style: TextStyle( + color: Colors.white, fontSize: 14), + ), + leading: Icon( + LineAwesomeIcons.cog, + color: Colors.white, + size: 22, + ))), + ), + Material( + color: Colors.transparent, + child: InkWell( + onTap: () => print("Help"), + child: ListTile( + title: Text( + "Help", + style: TextStyle( + color: Colors.white, fontSize: 14), + ), + leading: Icon( + LineAwesomeIcons.info_circle, + color: Colors.white, + size: 22, + ))), + ), + Material( + color: Colors.transparent, + child: InkWell( + onTap: () => print("Contact us"), + child: ListTile( + title: Text( + "Contact", + style: TextStyle( + color: Colors.white, fontSize: 14), + ), + leading: Icon( + Icons.mail_outline, + color: Colors.white, + size: 22, + ))), + ), + Padding( + padding: + const EdgeInsets.only(top: 24.0, bottom: 24.0), + child: Container( + height: 1, + color: Colors.grey, + ), + ), + isSignedIn + ? Padding( + padding: const EdgeInsets.only(bottom: 18.0), + child: Material( + color: Colors.transparent, + child: InkWell( + onTap: () => AuthService().signOut(), + child: ListTile( + title: Text( + "Logout", + style: TextStyle( + color: Colors.grey, + fontSize: 16), + ), + leading: Icon( + Icons.exit_to_app, + color: Colors.grey, + size: 22, + ))), + ), + ) + : Padding( + padding: const EdgeInsets.only(bottom: 18.0), + child: Material( + color: Colors.transparent, + child: InkWell( + onTap: () => print("Sign in"), + child: ListTile( + title: Text( + "Log in", + style: TextStyle( + color: Colors.white, + fontSize: 16), + ), + leading: Icon( + Icons.person_outline, + color: Colors.white, + size: 22, + ))), + ), + ), + ], + ), + ), + ), + ], + ), + ), + dragUpdate < 1 + ? BackdropFilter( + filter: ImageFilter.blur( + sigmaX: (10 - dragUpdate * 10), + sigmaY: (10 - dragUpdate * 10)), + child: Container( + decoration: BoxDecoration( + color: Colors.black.withOpacity(0), + ), + ), + ) + : null, + ].where((a) => a != null).toList(), + )), + ); + } +} diff --git a/lib/screens/fragments/templates/destination_view.dart b/lib/screens/fragments/templates/destination_view.dart new file mode 100644 index 0000000..1fef7bc --- /dev/null +++ b/lib/screens/fragments/templates/destination_view.dart @@ -0,0 +1,177 @@ +import 'package:digamobile/styles/constants.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:line_awesome_icons/line_awesome_icons.dart'; + +class DestinationView extends StatefulWidget { + DestinationView({Key key, this.destination}) : super(key: key); + final PageDestination destination; + + @override + _DestinationViewState createState() => _DestinationViewState(); +} + +class PageDestination { + final index; + final String title; + final IconData icon; + final IconData activeIcon; + final MaterialColor materialColor; + final Color materialColorLight; + + const PageDestination( + this.title, this.materialColor, this.icon, this.activeIcon, this.index, + {this.materialColorLight: Colors.white}); +} + +class _DestinationViewState extends State { + @override + Widget build(BuildContext context) { + return Navigator( + onGenerateRoute: (RouteSettings settings) { + return MaterialPageRoute( + settings: settings, + builder: (BuildContext context) { + switch (settings.name) { + case '/': + return RootPage(destination: widget.destination); + case '/list': + return ListPage(destination: widget.destination); + case '/text': + return TextPage(destination: widget.destination); + } + }, + ); + }, + ); + } +} + +class RootPage extends StatelessWidget { + const RootPage({Key key, this.destination}) : super(key: key); + + final PageDestination destination; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(destination.title), + backgroundColor: destination.materialColor, + ), + backgroundColor: destination.materialColor[50], + body: SizedBox.expand( + child: InkWell( + onTap: () { + Navigator.pushNamed(context, "/list"); + }, + ), + ), + ); + } +} + +class ListPage extends StatelessWidget { + const ListPage({Key key, this.destination}) : super(key: key); + + final PageDestination destination; + + @override + Widget build(BuildContext context) { + const List shades = [ + 50, + 100, + 200, + 300, + 400, + 500, + 600, + 700, + 800, + 900 + ]; + + return Scaffold( + appBar: AppBar( + title: Text(destination.title), + backgroundColor: destination.materialColor, + ), + backgroundColor: destination.materialColor[50], + body: SizedBox.expand( + child: ListView.builder( + itemCount: shades.length, + itemBuilder: (BuildContext context, int index) { + return SizedBox( + height: 128, + child: Card( + color: + destination.materialColor[shades[index]].withOpacity(0.25), + child: InkWell( + onTap: () { + Navigator.pushNamed(context, "/text"); + }, + child: Center( + child: Text('Item $index', + style: Theme.of(context).primaryTextTheme.display1), + ), + ), + ), + ); + }, + ), + ), + ); + } +} + +class TextPage extends StatefulWidget { + const TextPage({Key key, this.destination}) : super(key: key); + + final PageDestination destination; + + @override + _TextPageState createState() => _TextPageState(); +} + +class _TextPageState extends State { + TextEditingController _textController; + + @override + void initState() { + super.initState(); + _textController = TextEditingController( + text: 'sample text: ${widget.destination.title}', + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(widget.destination.title), + backgroundColor: widget.destination.materialColor, + ), + backgroundColor: widget.destination.materialColor[50], + body: Container( + padding: const EdgeInsets.all(32.0), + alignment: Alignment.center, + child: TextField(controller: _textController), + ), + ); + } + + @override + void dispose() { + _textController.dispose(); + super.dispose(); + } +} + +//The destination information for the bottom navigation +List allDestinations = [ + PageDestination('Home', Colors.blue, CupertinoIcons.home, Icons.home, + Constants.HOME_MAIN_PAGE), + PageDestination('Appointments', Colors.blue, CupertinoIcons.book, + CupertinoIcons.book_solid, Constants.APPOINTMENTS_MAIN_PAGE), +]; diff --git a/lib/screens/home_page.dart b/lib/screens/home_page.dart index acf5188..502623f 100644 --- a/lib/screens/home_page.dart +++ b/lib/screens/home_page.dart @@ -43,4 +43,4 @@ class HomePage extends StatelessWidget { ), floatingActionButton: new IncreaseCountButton()); } -} \ No newline at end of file +} diff --git a/lib/styles/constants.dart b/lib/styles/constants.dart new file mode 100644 index 0000000..fc4ac72 --- /dev/null +++ b/lib/styles/constants.dart @@ -0,0 +1,5 @@ +class Constants { + ///Main Route Pages + static const HOME_MAIN_PAGE = 0; + static const APPOINTMENTS_MAIN_PAGE = 1; +} diff --git a/pubspec.lock b/pubspec.lock index 09be7ec..188cd45 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -64,6 +64,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.1.3" + custom_navigator: + dependency: "direct main" + description: + name: custom_navigator + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.0" + dash_chat: + dependency: "direct main" + description: + name: dash_chat + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.16" firebase: dependency: transitive description: @@ -118,6 +132,20 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_inner_drawer: + dependency: "direct main" + description: + name: flutter_inner_drawer + url: "https://pub.dartlang.org" + source: hosted + version: "0.5.4" + flutter_parsed_text: + dependency: transitive + description: + name: flutter_parsed_text + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.3" flutter_redux: dependency: "direct main" description: @@ -135,6 +163,13 @@ packages: description: flutter source: sdk version: "0.0.0" + font_awesome_flutter: + dependency: "direct main" + description: + name: font_awesome_flutter + url: "https://pub.dartlang.org" + source: hosted + version: "8.7.0" google_sign_in: dependency: "direct main" description: @@ -177,6 +212,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.4" + intl: + dependency: transitive + description: + name: intl + url: "https://pub.dartlang.org" + source: hosted + version: "0.16.1" js: dependency: transitive description: @@ -184,6 +226,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.6.1+1" + line_awesome_icons: + dependency: "direct main" + description: + name: line_awesome_icons + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.4+2" logging: dependency: transitive description: @@ -301,6 +350,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.2.14" + transparent_image: + dependency: transitive + description: + name: transparent_image + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" typed_data: dependency: transitive description: @@ -308,6 +364,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.6" + uuid: + dependency: transitive + description: + name: uuid + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.4" vector_math: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index a1740c5..3d5da4b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -24,9 +24,14 @@ dependencies: redux_logging: ^0.4.0 firebase_auth: 0.15.3 google_sign_in: ^4.1.1 + dash_chat: ^1.0.16 + custom_navigator: ^0.3.0 + flutter_inner_drawer: ^0.5.4 # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^0.1.2 + font_awesome_flutter: ^8.5.0 + line_awesome_icons: ^1.0.4+2 dependency_overrides: firebase_core: 0.4.4 @@ -34,30 +39,24 @@ dependency_overrides: dev_dependencies: flutter_test: sdk: flutter - # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec # The following section is specific to Flutter. flutter: - # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. uses-material-design: true - # To add assets to your application, add an assets section, like this: # assets: # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg - # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware. - # For details regarding adding assets from package dependencies, see # https://flutter.dev/assets-and-images/#from-packages - # To add custom fonts to your application, add a fonts section here, # in this "flutter" section. Each entry in this list should have a # "family" key with the font family name, and a "fonts" key with a From 6bf18deb03fa66630fa208cfb971525885619930 Mon Sep 17 00:00:00 2001 From: David-solly Date: Tue, 3 Mar 2020 00:35:39 +0000 Subject: [PATCH 03/10] Added routing for chat --- android/app/src/main/AndroidManifest.xml | 22 +-- android/settings_aar.gradle | 1 + lib/actions/messaging_actions.dart | 13 ++ lib/screens/app_base_screen.dart | 24 +-- lib/screens/authentication_service.dart | 4 +- lib/screens/fragments/chat_fragment.dart | 155 +++++++++++++++++- .../navigation_drawers/navigation_drawer.dart | 52 +----- lib/screens/home_page.dart | 111 +++++++++---- lib/styles/constants.dart | 9 + pubspec.lock | 21 +++ pubspec.yaml | 4 +- 11 files changed, 309 insertions(+), 107 deletions(-) create mode 100644 android/settings_aar.gradle create mode 100644 lib/actions/messaging_actions.dart diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index be4a01e..4c04832 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,21 +1,13 @@ - + - - + + + + @@ -23,8 +15,6 @@ - + diff --git a/android/settings_aar.gradle b/android/settings_aar.gradle new file mode 100644 index 0000000..e7b4def --- /dev/null +++ b/android/settings_aar.gradle @@ -0,0 +1 @@ +include ':app' diff --git a/lib/actions/messaging_actions.dart b/lib/actions/messaging_actions.dart new file mode 100644 index 0000000..08235f7 --- /dev/null +++ b/lib/actions/messaging_actions.dart @@ -0,0 +1,13 @@ +class AddMessage { + final payload; + + AddMessage(this.payload); +} + +class AddAllMessages { + final payload; + + AddAllMessages(this.payload); +} + +class DeleteAllMessages {} diff --git a/lib/screens/app_base_screen.dart b/lib/screens/app_base_screen.dart index 5c7db43..3f56def 100644 --- a/lib/screens/app_base_screen.dart +++ b/lib/screens/app_base_screen.dart @@ -9,8 +9,8 @@ import 'package:line_awesome_icons/line_awesome_icons.dart'; import 'home_page.dart'; class AppBase extends StatefulWidget { - AppBase({Key key}) : super(key: key); - + AppBase({Key key, this.isLoggedIn}) : super(key: key); + final isLoggedIn; @override _AppBaseState createState() => _AppBaseState(); } @@ -73,7 +73,7 @@ class _AppBaseState extends State with TickerProviderStateMixin { tapScaffoldEnabled: _tapScaffold, offset: IDOffset.horizontal(_offset), - swipe: !_swipe, + swipe: _swipe, boxShadow: _direction == InnerDrawerDirection.start && _animationType == InnerDrawerAnimation.linear ? [] @@ -81,7 +81,10 @@ class _AppBaseState extends State with TickerProviderStateMixin { colorTransition: currentColor, leftAnimationType: _animationType, rightAnimationType: InnerDrawerAnimation.linear, - leftChild: NavigationDrawer(dragUpdate: _dragUpdate), + leftChild: NavigationDrawer( + dragUpdate: _dragUpdate, + isSignedIn: widget.isLoggedIn, + ), //rightChild: MapFilterDrawer(), @@ -93,12 +96,9 @@ class _AppBaseState extends State with TickerProviderStateMixin { scaffold: Scaffold( floatingActionButton: FloatingActionButton.extended( onPressed: () {}, - label: Padding( - padding: const EdgeInsets.only(left: 8.0), - child: Text("Chat Assist"), - ), + label: Text("Appointment"), icon: Icon( - Icons.chat, + Icons.add, color: allDestinations[_index].materialColorLight, ), ), @@ -134,9 +134,9 @@ class _AppBaseState extends State with TickerProviderStateMixin { child: KeyedSubtree( key: _destinationKeys[destination.index], child: _index == 0 - ? HomePage( - "Welcome", - ) + ? HomePage("Welcome", () { + _dragUpdate = 1.0; + }) : DestinationView( destination: destination, ), diff --git a/lib/screens/authentication_service.dart b/lib/screens/authentication_service.dart index f43a254..8f551ad 100644 --- a/lib/screens/authentication_service.dart +++ b/lib/screens/authentication_service.dart @@ -18,7 +18,9 @@ class AuthenticationService extends StatelessWidget { stream: FirebaseAuth.instance.onAuthStateChanged, builder: (context, snapshot) { if (snapshot.hasData) { - return AppBase(); + return AppBase( + isLoggedIn: true, + ); } else { return LoginScreen(); } diff --git a/lib/screens/fragments/chat_fragment.dart b/lib/screens/fragments/chat_fragment.dart index 44a534b..b2d8a6c 100644 --- a/lib/screens/fragments/chat_fragment.dart +++ b/lib/screens/fragments/chat_fragment.dart @@ -1,9 +1,17 @@ import 'dart:async'; +import 'dart:io'; import 'package:dash_chat/dash_chat.dart'; +import 'package:digamobile/screens/fragments/templates/destination_view.dart'; import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:simple_permissions/simple_permissions.dart'; class ChatFragment extends StatefulWidget { + final PageDestination destination; + + const ChatFragment({Key key, this.destination}) : super(key: key); @override _ChatFragmentState createState() => _ChatFragmentState(); } @@ -11,6 +19,23 @@ class ChatFragment extends StatefulWidget { class _ChatFragmentState extends State { final GlobalKey _chatViewKey = GlobalKey(); + File _image; + + Future getImage() async { + PermissionStatus permissionResult = + await SimplePermissions.requestPermission( + Permission.WriteExternalStorage); + if (permissionResult == PermissionStatus.authorized) { + // code of read or write file in external storage (SD card) + + var image = await ImagePicker.pickImage(source: ImageSource.gallery); + + setState(() { + _image = image; + }); + } + } + final ChatUser user = ChatUser( name: "Fayeed", uid: "123456789", @@ -63,7 +88,10 @@ class _ChatFragmentState extends State { Timer(Duration(milliseconds: 300), () { if (i < 6) { setState(() { - messages = [...messages, m[i]]; + //messages = [...messages, m[i]]; + messages = [] + ..addAll(messages) + ..add(m[i]); }); i++; } @@ -91,7 +119,10 @@ class _ChatFragmentState extends State { // ); // }); setState(() { - messages = [...messages, message]; + //messages = [...messages, message]; + messages = [] + ..addAll(messages) + ..add(message); print(messages.length); }); @@ -107,7 +138,123 @@ class _ChatFragmentState extends State { @override Widget build(BuildContext context) { - // TODO: implement build - throw UnimplementedError(); + return Scaffold( + appBar: CupertinoNavigationBar(), + body: DashChat( + height: MediaQuery.of(context).size.height - 60.0, + key: _chatViewKey, + inverted: false, + onSend: onSend, + user: user, + inputDecoration: + InputDecoration.collapsed(hintText: "Add message here..."), + dateFormat: DateFormat('yyyy-MMM-dd'), + timeFormat: DateFormat('HH:mm'), + messages: messages, + showUserAvatar: true, + showAvatarForEveryMessage: false, + scrollToBottom: true, + // inputFooterBuilder: () { + // return Column( + // children: [ + // Text('asd'), + // Text('asd'), + // Text('asd'), + // Text('asd'), + // Text('asd'), + // Text('asd'), + // ], + // ); + // }, + onPressAvatar: (ChatUser user) { + print("OnPressAvatar: ${user.name}"); + }, + onLongPressAvatar: (ChatUser user) { + print("OnLongPressAvatar: ${user.name}"); + }, + inputMaxLines: 5, + alwaysShowSend: true, + inputTextStyle: TextStyle(fontSize: 16.0), + inputContainerStyle: BoxDecoration( + border: Border.all(width: 0.0), + color: Colors.white, + ), + onQuickReply: (Reply reply) { + setState(() { + messages.add(ChatMessage( + text: reply.value, createdAt: DateTime.now(), user: user)); + + messages = []..addAll(messages); + }); + + Timer(Duration(milliseconds: 300), () { + _chatViewKey.currentState.scrollController + ..animateTo( + _chatViewKey + .currentState.scrollController.position.maxScrollExtent, + curve: Curves.easeOut, + duration: const Duration(milliseconds: 300), + ); + + if (i == 0) { + systemMessage(); + Timer(Duration(milliseconds: 600), () { + systemMessage(); + }); + } else { + systemMessage(); + } + }); + }, + onLoadEarlier: () { + print("laoding..."); + }, + shouldShowLoadEarlier: false, + showTraillingBeforeSend: true, + trailing: [ + IconButton( + icon: Icon(Icons.photo), + onPressed: () async { + File result = await ImagePicker.pickImage( + source: ImageSource.gallery, + maxHeight: 400, + maxWidth: 400, + ); + + // if (result != null) { + // final StorageReference storageRef = + // FirebaseStorage.instance.ref().child("chat_images"); + + // StorageUploadTask uploadTask = storageRef.putFile( + // result, + // StorageMetadata( + // contentType: 'image/jpg', + // ), + // ); + // StorageTaskSnapshot download = + // await uploadTask.onComplete; + + // String url = await download.ref.getDownloadURL(); + + // ChatMessage message = + // ChatMessage(text: "", user: user, image: url); + + // var documentReference = Firestore.instance + // .collection('messages') + // .document( + // DateTime.now().millisecondsSinceEpoch.toString()); + + // Firestore.instance.runTransaction((transaction) async { + // await transaction.set( + // documentReference, + // message.toJson(), + // ); + // }); + // } + }, + ) + ], + ), + ); } } diff --git a/lib/screens/fragments/navigation_drawers/navigation_drawer.dart b/lib/screens/fragments/navigation_drawers/navigation_drawer.dart index dea4163..f4da4bc 100644 --- a/lib/screens/fragments/navigation_drawers/navigation_drawer.dart +++ b/lib/screens/fragments/navigation_drawers/navigation_drawer.dart @@ -6,10 +6,10 @@ import 'package:line_awesome_icons/line_awesome_icons.dart'; import '../../../auth_service.dart'; class NavigationDrawer extends StatelessWidget { - NavigationDrawer({Key key, this.dragUpdate: 0}) : super(key: key); + NavigationDrawer({Key key, this.dragUpdate: 0, this.isSignedIn: false}) + : super(key: key); final double dragUpdate; - final availableSos = false; - final isSignedIn = false; + final isSignedIn; final hasRated = false; @override Widget build(BuildContext context) { @@ -91,45 +91,7 @@ class NavigationDrawer extends StatelessWidget { ))), ), Padding( - padding: const EdgeInsets.only(bottom: 24.0), - child: Container( - height: 1, - color: Colors.grey, - ), - ), - Material( - color: availableSos - ? Colors.red[800] - : Colors.red.shade900.withAlpha(150), - child: InkWell( - onTap: () => print("Sos"), - child: ListTile( - title: Text( - "S.O.S", - style: TextStyle( - color: availableSos - ? Colors.white - : Colors.grey.shade300, - fontSize: 14), - ), - trailing: availableSos - ? Icon( - Icons.adjust, - color: Colors.green[300], - ) - : Icon( - Icons.album, - color: Colors.red[700].withAlpha(150), - ), - leading: Icon( - LineAwesomeIcons.exclamation_triangle, - //FontAwesomeIcons.exclamationTriangle, - color: Colors.white, - size: 22, - ))), - ), - Padding( - padding: const EdgeInsets.only(top: 24.0), + padding: const EdgeInsets.only(top: 12.0), child: Container( height: 1, color: Colors.grey, @@ -216,14 +178,14 @@ class NavigationDrawer extends StatelessWidget { onTap: () => AuthService().signOut(), child: ListTile( title: Text( - "Logout", + "Sign Out", style: TextStyle( - color: Colors.grey, + color: Colors.white, fontSize: 16), ), leading: Icon( Icons.exit_to_app, - color: Colors.grey, + color: Colors.white, size: 22, ))), ), diff --git a/lib/screens/home_page.dart b/lib/screens/home_page.dart index 502623f..fc22e19 100644 --- a/lib/screens/home_page.dart +++ b/lib/screens/home_page.dart @@ -1,46 +1,101 @@ import 'package:digamobile/auth_service.dart'; import 'package:digamobile/containers/counter/counter.dart'; import 'package:digamobile/containers/counter/increase_counter.dart'; +import 'package:digamobile/screens/fragments/chat_fragment.dart'; +import 'package:digamobile/screens/fragments/templates/destination_view.dart'; +import 'package:digamobile/styles/constants.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; class HomePage extends StatelessWidget { final String title; + //Call back to pass menu click event to the app base to open the app drawer + final Function() MenuClicked; + final PageDestination destination; - HomePage(this.title); + HomePage(this.title, this.MenuClicked, {this.destination}); + + @override + Widget build(BuildContext context) { + return Navigator( + onGenerateRoute: (RouteSettings settings) { + return MaterialPageRoute( + settings: settings, + builder: (BuildContext context) { + switch (settings.name) { + case ConstantsRoutes.HOME_ROOT_PAGE: + return _HomeScreen( + destination: destination, + title: title, + ); + case ConstantsRoutes.HOME_CHAT_PAGE: + return ChatFragment(destination: destination); + } + }, + ); + }, + ); + } +} + +class _HomeScreen extends StatelessWidget { + const _HomeScreen({Key key, this.title, this.menuClicked, this.destination}) + : super(key: key); + final String title; + //Call back to pass menu click event to the app base to open the app drawer + final Function() menuClicked; + final PageDestination destination; @override Widget build(BuildContext context) { return new Scaffold( - backgroundColor: Colors.grey[50], - appBar: new AppBar( - title: new Text(this.title), - backgroundColor: Colors.white, - elevation: 0.0, + backgroundColor: Colors.grey[50], + appBar: new AppBar( + centerTitle: true, + title: new Text( + this.title, + style: TextStyle(color: Colors.grey.shade800, fontSize: 14), ), - body: new Container( - child: new Center( - child: new Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text('You are logged in'), - SizedBox(height: 10.0), - RaisedButton( - onPressed: () { - AuthService().signOut(); - }, - child: Center( - child: Text('Sign Out'), - ), - color: Colors.red, - ), - new Text( - 'You have pushed the button this many times:', - ), - new Counter(), - ], + backgroundColor: Colors.white, + elevation: 0.0, + leading: IconButton( + icon: Icon( + Icons.menu, + color: Colors.grey.shade900, ), + onPressed: () {}), + ), + body: new Container( + child: new Center( + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('You are logged in'), + SizedBox(height: 10.0), + RaisedButton( + onPressed: () { + AuthService().signOut(); + }, + child: Center( + child: Text('Sign Out'), + ), + color: Colors.red, + ), + new Text( + 'You have pushed the button this many times:', + ), + new Counter(), + ], ), ), - floatingActionButton: new IncreaseCountButton()); + ), + //floatingActionButton: new IncreaseCountButton()); + floatingActionButton: FloatingActionButton( + onPressed: () => + Navigator.of(context).pushNamed(ConstantsRoutes.HOME_CHAT_PAGE), + child: Icon(Icons.chat), + ), + resizeToAvoidBottomInset: true, + ); } } diff --git a/lib/styles/constants.dart b/lib/styles/constants.dart index fc4ac72..e47e323 100644 --- a/lib/styles/constants.dart +++ b/lib/styles/constants.dart @@ -3,3 +3,12 @@ class Constants { static const HOME_MAIN_PAGE = 0; static const APPOINTMENTS_MAIN_PAGE = 1; } + +///Provides const values used in routing the app from page to page +class ConstantsRoutes { + ///'/' : Reperesents the root page of the [HomePage] + static const HOME_ROOT_PAGE = "/"; + + ///'/chat' : Represents the [ChatFragment] page - from the [HomePage] base + static const HOME_CHAT_PAGE = "/chat"; +} diff --git a/pubspec.lock b/pubspec.lock index 188cd45..66abab1 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -146,6 +146,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.3" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.6" flutter_redux: dependency: "direct main" description: @@ -212,6 +219,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.4" + image_picker: + dependency: "direct main" + description: + name: image_picker + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.3+4" intl: dependency: transitive description: @@ -303,6 +317,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.4.0" + simple_permissions: + dependency: "direct main" + description: + name: simple_permissions + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.9" sky_engine: dependency: transitive description: flutter diff --git a/pubspec.yaml b/pubspec.yaml index 3d5da4b..3ceaec2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -14,7 +14,7 @@ description: A new Flutter project. version: 1.0.0+1 environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.6.0 <3.0.0" dependencies: flutter: @@ -32,6 +32,8 @@ dependencies: cupertino_icons: ^0.1.2 font_awesome_flutter: ^8.5.0 line_awesome_icons: ^1.0.4+2 + image_picker: ^0.6.3+4 + simple_permissions: ^0.1.9 dependency_overrides: firebase_core: 0.4.4 From 2aedad1d64c521c639e09ec8682fdd6d58c675dc Mon Sep 17 00:00:00 2001 From: David-solly Date: Tue, 3 Mar 2020 02:09:24 +0000 Subject: [PATCH 04/10] Added chat ui --- .../gradle/wrapper/gradle-wrapper.properties | 1 + lib/screens/app_base_screen.dart | 54 +++- lib/screens/fragments/chat_fragment.dart | 270 +++++++++--------- lib/screens/home_page.dart | 36 ++- pubspec.lock | 7 - pubspec.yaml | 1 - 6 files changed, 208 insertions(+), 161 deletions(-) diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index d23770e..779f777 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -4,3 +4,4 @@ distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip + diff --git a/lib/screens/app_base_screen.dart b/lib/screens/app_base_screen.dart index 3f56def..dc591e8 100644 --- a/lib/screens/app_base_screen.dart +++ b/lib/screens/app_base_screen.dart @@ -22,9 +22,13 @@ class _AppBaseState extends State with TickerProviderStateMixin { bool _onTapToClose = false; bool _swipe = true; bool _tapScaffold = true; + bool _isChatEnabled = true; InnerDrawerAnimation _animationType = InnerDrawerAnimation.static; double _offset = 0.4; + AnimationController _controller; + Animation _drawerState; + double _dragUpdate = 0; int _index = 0; InnerDrawerDirection _direction = InnerDrawerDirection.start; @@ -44,7 +48,22 @@ class _AppBaseState extends State with TickerProviderStateMixin { @override void initState() { print("@@@@----MAIN____APPP____INIT___STATE"); - + _controller = + AnimationController(vsync: this, duration: Duration(milliseconds: 500)); + _drawerState = Tween(begin: 0.0, end: 1.0).animate(_controller); + _controller.addListener(() { + print("animating ${_drawerState.value}"); + + print("Clicked"); + _direction = InnerDrawerDirection.start; + setState(() => _dragUpdate = _drawerState.value); + }); + _drawerState.addListener(() { + setState(() { + print("Clicked"); + this._dragUpdate = _drawerState.value; + }); + }); _faders = allDestinations.map((PageDestination destination) { return AnimationController( @@ -94,14 +113,16 @@ class _AppBaseState extends State with TickerProviderStateMixin { }, //innerDrawerCallback: (a) => print(a), scaffold: Scaffold( - floatingActionButton: FloatingActionButton.extended( - onPressed: () {}, - label: Text("Appointment"), - icon: Icon( - Icons.add, - color: allDestinations[_index].materialColorLight, - ), - ), + floatingActionButton: _isChatEnabled + ? null + : FloatingActionButton.extended( + onPressed: () {}, + label: Text("Appointment"), + icon: Icon( + Icons.add, + color: allDestinations[_index].materialColorLight, + ), + ), floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked, extendBody: false, @@ -134,9 +155,18 @@ class _AppBaseState extends State with TickerProviderStateMixin { child: KeyedSubtree( key: _destinationKeys[destination.index], child: _index == 0 - ? HomePage("Welcome", () { - _dragUpdate = 1.0; - }) + ? HomePage( + "Welcome", + menuClicked: () { + print("clicked in base"); + _controller.status == AnimationStatus.completed || + _controller.status == + AnimationStatus.reverse + ? _controller.forward() + : _controller.reverse(); + _controller.forward(); + }, + ) : DestinationView( destination: destination, ), diff --git a/lib/screens/fragments/chat_fragment.dart b/lib/screens/fragments/chat_fragment.dart index b2d8a6c..cd6997b 100644 --- a/lib/screens/fragments/chat_fragment.dart +++ b/lib/screens/fragments/chat_fragment.dart @@ -6,12 +6,14 @@ import 'package:digamobile/screens/fragments/templates/destination_view.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; -import 'package:simple_permissions/simple_permissions.dart'; class ChatFragment extends StatefulWidget { final PageDestination destination; - const ChatFragment({Key key, this.destination}) : super(key: key); + const ChatFragment({ + Key key, + this.destination, + }) : super(key: key); @override _ChatFragmentState createState() => _ChatFragmentState(); } @@ -22,18 +24,18 @@ class _ChatFragmentState extends State { File _image; Future getImage() async { - PermissionStatus permissionResult = - await SimplePermissions.requestPermission( - Permission.WriteExternalStorage); - if (permissionResult == PermissionStatus.authorized) { - // code of read or write file in external storage (SD card) + // PermissionStatus permissionResult = + // await SimplePermissions.requestPermission( + // Permission.WriteExternalStorage); + // if (permissionResult == PermissionStatus.authorized) { + // // code of read or write file in external storage (SD card) - var image = await ImagePicker.pickImage(source: ImageSource.gallery); + var image = await ImagePicker.pickImage(source: ImageSource.gallery); - setState(() { - _image = image; - }); - } + setState(() { + _image = image; + }); + //} } final ChatUser user = ChatUser( @@ -66,21 +68,6 @@ class _ChatFragmentState extends State { ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), ]); } @@ -139,120 +126,139 @@ class _ChatFragmentState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: CupertinoNavigationBar(), - body: DashChat( - height: MediaQuery.of(context).size.height - 60.0, - key: _chatViewKey, - inverted: false, - onSend: onSend, - user: user, - inputDecoration: - InputDecoration.collapsed(hintText: "Add message here..."), - dateFormat: DateFormat('yyyy-MMM-dd'), - timeFormat: DateFormat('HH:mm'), - messages: messages, - showUserAvatar: true, - showAvatarForEveryMessage: false, - scrollToBottom: true, - // inputFooterBuilder: () { - // return Column( - // children: [ - // Text('asd'), - // Text('asd'), - // Text('asd'), - // Text('asd'), - // Text('asd'), - // Text('asd'), - // ], - // ); - // }, - onPressAvatar: (ChatUser user) { - print("OnPressAvatar: ${user.name}"); - }, - onLongPressAvatar: (ChatUser user) { - print("OnLongPressAvatar: ${user.name}"); - }, - inputMaxLines: 5, - alwaysShowSend: true, - inputTextStyle: TextStyle(fontSize: 16.0), - inputContainerStyle: BoxDecoration( - border: Border.all(width: 0.0), - color: Colors.white, - ), - onQuickReply: (Reply reply) { - setState(() { - messages.add(ChatMessage( - text: reply.value, createdAt: DateTime.now(), user: user)); + extendBody: false, + appBar: CupertinoNavigationBar( + automaticallyImplyMiddle: true, + automaticallyImplyLeading: true, + leading: IconButton( + icon: Icon(CupertinoIcons.back), + onPressed: () { + if (Navigator.of(context).canPop()) Navigator.of(context).pop(); + }), + ), + body: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Flexible( + flex: 1, + child: DashChat( + height: MediaQuery.of(context).size.height - 120.0, + key: _chatViewKey, + inverted: false, + onSend: onSend, + user: user, - messages = []..addAll(messages); - }); + inputDecoration: InputDecoration(hintText: "Add message here..."), + dateFormat: DateFormat('yyyy-MMM-dd'), + timeFormat: DateFormat('HH:mm'), + messages: messages, + showUserAvatar: true, + showAvatarForEveryMessage: false, + scrollToBottom: true, + // inputFooterBuilder: () { + // return Column( + // children: [ + // Text('asd'), + // Text('asd'), + // Text('asd'), + // Text('asd'), + // Text('asd'), + // Text('asd'), + // ], + // ); + // }, + onPressAvatar: (ChatUser user) { + print("OnPressAvatar: ${user.name}"); + }, + onLongPressAvatar: (ChatUser user) { + print("OnLongPressAvatar: ${user.name}"); + }, + inputMaxLines: 5, + alwaysShowSend: true, + inputTextStyle: TextStyle(fontSize: 16.0), + inputContainerStyle: BoxDecoration( + border: Border.all(width: 0.0), + color: Colors.white, + ), + onQuickReply: (Reply reply) { + setState(() { + messages.add(ChatMessage( + text: reply.value, + createdAt: DateTime.now(), + user: user)); - Timer(Duration(milliseconds: 300), () { - _chatViewKey.currentState.scrollController - ..animateTo( - _chatViewKey - .currentState.scrollController.position.maxScrollExtent, - curve: Curves.easeOut, - duration: const Duration(milliseconds: 300), - ); + messages = []..addAll(messages); + }); - if (i == 0) { - systemMessage(); - Timer(Duration(milliseconds: 600), () { - systemMessage(); - }); - } else { - systemMessage(); - } - }); - }, - onLoadEarlier: () { - print("laoding..."); - }, - shouldShowLoadEarlier: false, - showTraillingBeforeSend: true, - trailing: [ - IconButton( - icon: Icon(Icons.photo), - onPressed: () async { - File result = await ImagePicker.pickImage( - source: ImageSource.gallery, - maxHeight: 400, - maxWidth: 400, - ); + Timer(Duration(milliseconds: 300), () { + _chatViewKey.currentState.scrollController + ..animateTo( + _chatViewKey.currentState.scrollController.position + .maxScrollExtent, + curve: Curves.easeOut, + duration: const Duration(milliseconds: 300), + ); - // if (result != null) { - // final StorageReference storageRef = - // FirebaseStorage.instance.ref().child("chat_images"); + if (i == 0) { + systemMessage(); + Timer(Duration(milliseconds: 600), () { + systemMessage(); + }); + } else { + systemMessage(); + } + }); + }, + onLoadEarlier: () { + print("laoding..."); + }, + shouldShowLoadEarlier: false, + showTraillingBeforeSend: true, + trailing: [ + IconButton( + icon: Icon(Icons.photo), + onPressed: () async { + File result = await ImagePicker.pickImage( + source: ImageSource.gallery, + maxHeight: 400, + maxWidth: 400, + ); - // StorageUploadTask uploadTask = storageRef.putFile( - // result, - // StorageMetadata( - // contentType: 'image/jpg', - // ), - // ); - // StorageTaskSnapshot download = - // await uploadTask.onComplete; + // if (result != null) { + // final StorageReference storageRef = + // FirebaseStorage.instance.ref().child("chat_images"); + + // StorageUploadTask uploadTask = storageRef.putFile( + // result, + // StorageMetadata( + // contentType: 'image/jpg', + // ), + // ); + // StorageTaskSnapshot download = + // await uploadTask.onComplete; - // String url = await download.ref.getDownloadURL(); + // String url = await download.ref.getDownloadURL(); - // ChatMessage message = - // ChatMessage(text: "", user: user, image: url); + // ChatMessage message = + // ChatMessage(text: "", user: user, image: url); - // var documentReference = Firestore.instance - // .collection('messages') - // .document( - // DateTime.now().millisecondsSinceEpoch.toString()); + // var documentReference = Firestore.instance + // .collection('messages') + // .document( + // DateTime.now().millisecondsSinceEpoch.toString()); - // Firestore.instance.runTransaction((transaction) async { - // await transaction.set( - // documentReference, - // message.toJson(), - // ); - // }); - // } - }, - ) + // Firestore.instance.runTransaction((transaction) async { + // await transaction.set( + // documentReference, + // message.toJson(), + // ); + // }); + // } + }, + ) + ], + ), + ), ], ), ); diff --git a/lib/screens/home_page.dart b/lib/screens/home_page.dart index fc22e19..ffc6c9d 100644 --- a/lib/screens/home_page.dart +++ b/lib/screens/home_page.dart @@ -10,10 +10,14 @@ import 'package:flutter/material.dart'; class HomePage extends StatelessWidget { final String title; //Call back to pass menu click event to the app base to open the app drawer - final Function() MenuClicked; + final VoidCallback menuClicked; final PageDestination destination; - HomePage(this.title, this.MenuClicked, {this.destination}); + HomePage( + this.title, { + this.menuClicked, + this.destination, + }); @override Widget build(BuildContext context) { @@ -27,9 +31,15 @@ class HomePage extends StatelessWidget { return _HomeScreen( destination: destination, title: title, + menuClicked: () { + print("Clicked in home"); + this.menuClicked.call(); + }, ); case ConstantsRoutes.HOME_CHAT_PAGE: - return ChatFragment(destination: destination); + return ChatFragment( + destination: destination, + ); } }, ); @@ -39,11 +49,16 @@ class HomePage extends StatelessWidget { } class _HomeScreen extends StatelessWidget { - const _HomeScreen({Key key, this.title, this.menuClicked, this.destination}) - : super(key: key); + const _HomeScreen({ + Key key, + this.title, + this.menuClicked, + this.destination, + }) : super(key: key); final String title; //Call back to pass menu click event to the app base to open the app drawer - final Function() menuClicked; + final VoidCallback menuClicked; + final PageDestination destination; @override @@ -63,7 +78,9 @@ class _HomeScreen extends StatelessWidget { Icons.menu, color: Colors.grey.shade900, ), - onPressed: () {}), + onPressed: () { + this.menuClicked.call(); + }), ), body: new Container( child: new Center( @@ -91,8 +108,9 @@ class _HomeScreen extends StatelessWidget { ), //floatingActionButton: new IncreaseCountButton()); floatingActionButton: FloatingActionButton( - onPressed: () => - Navigator.of(context).pushNamed(ConstantsRoutes.HOME_CHAT_PAGE), + onPressed: () { + Navigator.of(context).pushNamed(ConstantsRoutes.HOME_CHAT_PAGE); + }, child: Icon(Icons.chat), ), resizeToAvoidBottomInset: true, diff --git a/pubspec.lock b/pubspec.lock index 66abab1..07f1cc7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -317,13 +317,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.4.0" - simple_permissions: - dependency: "direct main" - description: - name: simple_permissions - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.9" sky_engine: dependency: transitive description: flutter diff --git a/pubspec.yaml b/pubspec.yaml index 3ceaec2..2396bd8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -33,7 +33,6 @@ dependencies: font_awesome_flutter: ^8.5.0 line_awesome_icons: ^1.0.4+2 image_picker: ^0.6.3+4 - simple_permissions: ^0.1.9 dependency_overrides: firebase_core: 0.4.4 From 5f78cb74097367260d8253a7e4aab309ae1de7ec Mon Sep 17 00:00:00 2001 From: David-solly Date: Mon, 2 Mar 2020 20:50:33 +0000 Subject: [PATCH 05/10] Initial commit --- pubspec.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.lock b/pubspec.lock index 49189c0..09be7ec 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -300,7 +300,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.11" + version: "0.2.14" typed_data: dependency: transitive description: From a401638a6a3a11edf7be7308dbc4f8d38904b585 Mon Sep 17 00:00:00 2001 From: David-solly Date: Mon, 2 Mar 2020 22:20:25 +0000 Subject: [PATCH 06/10] Added app navigation --- lib/screens/app_base_screen.dart | 160 ++++++++++ lib/screens/authentication_service.dart | 5 +- lib/screens/fragments/chat_fragment.dart | 113 ++++++++ .../navigation_drawers/navigation_drawer.dart | 274 ++++++++++++++++++ .../fragments/templates/destination_view.dart | 177 +++++++++++ lib/screens/home_page.dart | 2 +- lib/styles/constants.dart | 5 + pubspec.lock | 63 ++++ pubspec.yaml | 11 +- 9 files changed, 801 insertions(+), 9 deletions(-) create mode 100644 lib/screens/app_base_screen.dart create mode 100644 lib/screens/fragments/chat_fragment.dart create mode 100644 lib/screens/fragments/navigation_drawers/navigation_drawer.dart create mode 100644 lib/screens/fragments/templates/destination_view.dart create mode 100644 lib/styles/constants.dart diff --git a/lib/screens/app_base_screen.dart b/lib/screens/app_base_screen.dart new file mode 100644 index 0000000..5c7db43 --- /dev/null +++ b/lib/screens/app_base_screen.dart @@ -0,0 +1,160 @@ +import 'package:digamobile/screens/fragments/navigation_drawers/navigation_drawer.dart'; +import 'package:digamobile/screens/fragments/templates/destination_view.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_inner_drawer/inner_drawer.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:line_awesome_icons/line_awesome_icons.dart'; + +import 'home_page.dart'; + +class AppBase extends StatefulWidget { + AppBase({Key key}) : super(key: key); + + @override + _AppBaseState createState() => _AppBaseState(); +} + +class _AppBaseState extends State with TickerProviderStateMixin { + final GlobalKey _innerDrawerKey = + GlobalKey(); + + bool _onTapToClose = false; + bool _swipe = true; + bool _tapScaffold = true; + InnerDrawerAnimation _animationType = InnerDrawerAnimation.static; + double _offset = 0.4; + + double _dragUpdate = 0; + int _index = 0; + InnerDrawerDirection _direction = InnerDrawerDirection.start; + + Color pickerColor = Color(0xff443a49); + Color currentColor = Colors.black54; + ValueChanged onColorChanged; + +//navigation state + List _faders; + List _destinationKeys; + + // Custom navigator takes a global key if you want to access the + // navigator from outside it's widget tree subtree + GlobalKey navigatorKey = GlobalKey(); + + @override + void initState() { + print("@@@@----MAIN____APPP____INIT___STATE"); + + _faders = + allDestinations.map((PageDestination destination) { + return AnimationController( + vsync: this, duration: Duration(milliseconds: 500)); + }).toList(); + _faders[_index].value = 1.0; + _destinationKeys = + List.generate(allDestinations.length, (int index) => GlobalKey()) + .toList(); + + super.initState(); + } + + @override + void dispose() { + for (AnimationController controller in _faders) controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: InnerDrawer( + key: _innerDrawerKey, + onTapClose: _onTapToClose, + tapScaffoldEnabled: _tapScaffold, + + offset: IDOffset.horizontal(_offset), + swipe: !_swipe, + boxShadow: _direction == InnerDrawerDirection.start && + _animationType == InnerDrawerAnimation.linear + ? [] + : null, + colorTransition: currentColor, + leftAnimationType: _animationType, + rightAnimationType: InnerDrawerAnimation.linear, + leftChild: NavigationDrawer(dragUpdate: _dragUpdate), + + //rightChild: MapFilterDrawer(), + + onDragUpdate: (double val, InnerDrawerDirection direction) { + _direction = direction; + setState(() => _dragUpdate = val); + }, + //innerDrawerCallback: (a) => print(a), + scaffold: Scaffold( + floatingActionButton: FloatingActionButton.extended( + onPressed: () {}, + label: Padding( + padding: const EdgeInsets.only(left: 8.0), + child: Text("Chat Assist"), + ), + icon: Icon( + Icons.chat, + color: allDestinations[_index].materialColorLight, + ), + ), + floatingActionButtonLocation: + FloatingActionButtonLocation.centerDocked, + extendBody: false, + bottomNavigationBar: BottomNavigationBar( + //type: BottomNavigationBarType.fixed, + selectedIconTheme: IconThemeData(size: 26), + selectedItemColor: allDestinations[_index].materialColor, + unselectedItemColor: Colors.grey.shade900, + showUnselectedLabels: true, + onTap: (index) { + // navigatorKey.currentState.maybePop(); + setState(() => _index = index); + }, + currentIndex: _index, + items: allDestinations + .map((pageDestination) { + return BottomNavigationBarItem( + icon: Icon(pageDestination.icon), + activeIcon: Icon(pageDestination.activeIcon), + backgroundColor: pageDestination.materialColor, + title: Text(pageDestination.title)); + }).toList(), + ), + body: Stack( + fit: StackFit.expand, + children: allDestinations.map((PageDestination destination) { + final Widget view = FadeTransition( + opacity: _faders[destination.index] + .drive(CurveTween(curve: Curves.fastOutSlowIn)), + child: KeyedSubtree( + key: _destinationKeys[destination.index], + child: _index == 0 + ? HomePage( + "Welcome", + ) + : DestinationView( + destination: destination, + ), + ), + ); + if (destination.index == _index) { + _faders[destination.index].forward(); + return view; + } else { + _faders[destination.index].reverse(); + if (_faders[destination.index].isAnimating) { + return IgnorePointer(child: view); + } + return Offstage(child: view); + } + }).toList(), + )), + ), + ); + } +} diff --git a/lib/screens/authentication_service.dart b/lib/screens/authentication_service.dart index f5fc8ae..f43a254 100644 --- a/lib/screens/authentication_service.dart +++ b/lib/screens/authentication_service.dart @@ -1,4 +1,5 @@ import 'package:digamobile/login_screen.dart'; +import 'package:digamobile/screens/app_base_screen.dart'; import 'package:digamobile/screens/home_page.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; @@ -17,7 +18,7 @@ class AuthenticationService extends StatelessWidget { stream: FirebaseAuth.instance.onAuthStateChanged, builder: (context, snapshot) { if (snapshot.hasData) { - return HomePage(title); + return AppBase(); } else { return LoginScreen(); } @@ -26,4 +27,4 @@ class AuthenticationService extends StatelessWidget { ), ); } -} \ No newline at end of file +} diff --git a/lib/screens/fragments/chat_fragment.dart b/lib/screens/fragments/chat_fragment.dart new file mode 100644 index 0000000..44a534b --- /dev/null +++ b/lib/screens/fragments/chat_fragment.dart @@ -0,0 +1,113 @@ +import 'dart:async'; + +import 'package:dash_chat/dash_chat.dart'; +import 'package:flutter/cupertino.dart'; + +class ChatFragment extends StatefulWidget { + @override + _ChatFragmentState createState() => _ChatFragmentState(); +} + +class _ChatFragmentState extends State { + final GlobalKey _chatViewKey = GlobalKey(); + + final ChatUser user = ChatUser( + name: "Fayeed", + uid: "123456789", + avatar: "https://www.wrappixel.com/ampleadmin/assets/images/users/4.jpg", + ); + + final ChatUser otherUser = ChatUser( + name: "Mrfatty", + uid: "25649654", + ); + + List messages = List(); + + var m = List(); + + var i = 0; + + @override + void initState() { + super.initState(); + + messages.addAll([ + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), + ]); + } + + void systemMessage() { + Timer(Duration(milliseconds: 300), () { + if (i < 6) { + setState(() { + messages = [...messages, m[i]]; + }); + i++; + } + Timer(Duration(milliseconds: 300), () { + _chatViewKey.currentState.scrollController + ..animateTo( + _chatViewKey.currentState.scrollController.position.maxScrollExtent, + curve: Curves.easeOut, + duration: const Duration(milliseconds: 300), + ); + }); + }); + } + + void onSend(ChatMessage message) { + print(message.toJson()); + // var documentReference = Firestore.instance + // .collection('messages') + // .document(DateTime.now().millisecondsSinceEpoch.toString()); + + // Firestore.instance.runTransaction((transaction) async { + // await transaction.set( + // documentReference, + // message.toJson(), + // ); + // }); + setState(() { + messages = [...messages, message]; + print(messages.length); + }); + + if (i == 0) { + systemMessage(); + Timer(Duration(milliseconds: 600), () { + systemMessage(); + }); + } else { + systemMessage(); + } + } + + @override + Widget build(BuildContext context) { + // TODO: implement build + throw UnimplementedError(); + } +} diff --git a/lib/screens/fragments/navigation_drawers/navigation_drawer.dart b/lib/screens/fragments/navigation_drawers/navigation_drawer.dart new file mode 100644 index 0000000..dea4163 --- /dev/null +++ b/lib/screens/fragments/navigation_drawers/navigation_drawer.dart @@ -0,0 +1,274 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:line_awesome_icons/line_awesome_icons.dart'; + +import '../../../auth_service.dart'; + +class NavigationDrawer extends StatelessWidget { + NavigationDrawer({Key key, this.dragUpdate: 0}) : super(key: key); + final double dragUpdate; + final availableSos = false; + final isSignedIn = false; + final hasRated = false; + @override + Widget build(BuildContext context) { + return Container( + child: Material( + child: Stack( + children: [ + Container( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topRight, + end: Alignment.bottomLeft, + // Add one stop for each color. Stops should increase from 0 to 1 + //stops: [0.1, 0.5,0.5, 0.7, 0.9], + colors: [ + ColorTween( + begin: Colors.blueAccent, + end: Colors.blueGrey[400].withRed(100), + ).lerp(dragUpdate), + ColorTween( + begin: Colors.green, + end: Colors.blueGrey[800].withGreen(80), + ).lerp(dragUpdate), + ], + ), + ), + child: Stack( + fit: StackFit.expand, + children: [ + Padding( + padding: EdgeInsets.only(left: 30), + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Column( + children: [ + Container( + margin: EdgeInsets.only( + left: 10, bottom: 15, top: 72), + width: 80, + child: ClipRRect( + child: Container( + height: 90, + width: 90, + color: Colors.blueAccent, + ), + borderRadius: BorderRadius.circular(50), + ), + ), + Text( + "User", + style: + TextStyle(color: Colors.white, fontSize: 18), + ) + ], + //mainAxisAlignment: MainAxisAlignment.center, + ), + Padding( + padding: EdgeInsets.all(10), + ), + Material( + color: Colors.transparent, + child: InkWell( + onTap: () => print("Rate us"), + child: ListTile( + title: Text( + "Rate", + style: TextStyle( + color: Colors.white, fontSize: 14), + ), + leading: Icon( + hasRated + ? LineAwesomeIcons.star + : LineAwesomeIcons.star_o, + color: Colors.white, + size: 22, + ))), + ), + Padding( + padding: const EdgeInsets.only(bottom: 24.0), + child: Container( + height: 1, + color: Colors.grey, + ), + ), + Material( + color: availableSos + ? Colors.red[800] + : Colors.red.shade900.withAlpha(150), + child: InkWell( + onTap: () => print("Sos"), + child: ListTile( + title: Text( + "S.O.S", + style: TextStyle( + color: availableSos + ? Colors.white + : Colors.grey.shade300, + fontSize: 14), + ), + trailing: availableSos + ? Icon( + Icons.adjust, + color: Colors.green[300], + ) + : Icon( + Icons.album, + color: Colors.red[700].withAlpha(150), + ), + leading: Icon( + LineAwesomeIcons.exclamation_triangle, + //FontAwesomeIcons.exclamationTriangle, + color: Colors.white, + size: 22, + ))), + ), + Padding( + padding: const EdgeInsets.only(top: 24.0), + child: Container( + height: 1, + color: Colors.grey, + ), + ), + Material( + color: Colors.transparent, + child: InkWell( + onTap: () => print("My Account"), + child: ListTile( + title: Text( + "My Account", + style: TextStyle( + color: Colors.white, fontSize: 14), + ), + leading: Icon( + LineAwesomeIcons.lock, + color: Colors.white, + size: 22, + ))), + ), + Material( + color: Colors.transparent, + child: InkWell( + onTap: () => print("Settings"), + child: ListTile( + title: Text( + "Settings", + style: TextStyle( + color: Colors.white, fontSize: 14), + ), + leading: Icon( + LineAwesomeIcons.cog, + color: Colors.white, + size: 22, + ))), + ), + Material( + color: Colors.transparent, + child: InkWell( + onTap: () => print("Help"), + child: ListTile( + title: Text( + "Help", + style: TextStyle( + color: Colors.white, fontSize: 14), + ), + leading: Icon( + LineAwesomeIcons.info_circle, + color: Colors.white, + size: 22, + ))), + ), + Material( + color: Colors.transparent, + child: InkWell( + onTap: () => print("Contact us"), + child: ListTile( + title: Text( + "Contact", + style: TextStyle( + color: Colors.white, fontSize: 14), + ), + leading: Icon( + Icons.mail_outline, + color: Colors.white, + size: 22, + ))), + ), + Padding( + padding: + const EdgeInsets.only(top: 24.0, bottom: 24.0), + child: Container( + height: 1, + color: Colors.grey, + ), + ), + isSignedIn + ? Padding( + padding: const EdgeInsets.only(bottom: 18.0), + child: Material( + color: Colors.transparent, + child: InkWell( + onTap: () => AuthService().signOut(), + child: ListTile( + title: Text( + "Logout", + style: TextStyle( + color: Colors.grey, + fontSize: 16), + ), + leading: Icon( + Icons.exit_to_app, + color: Colors.grey, + size: 22, + ))), + ), + ) + : Padding( + padding: const EdgeInsets.only(bottom: 18.0), + child: Material( + color: Colors.transparent, + child: InkWell( + onTap: () => print("Sign in"), + child: ListTile( + title: Text( + "Log in", + style: TextStyle( + color: Colors.white, + fontSize: 16), + ), + leading: Icon( + Icons.person_outline, + color: Colors.white, + size: 22, + ))), + ), + ), + ], + ), + ), + ), + ], + ), + ), + dragUpdate < 1 + ? BackdropFilter( + filter: ImageFilter.blur( + sigmaX: (10 - dragUpdate * 10), + sigmaY: (10 - dragUpdate * 10)), + child: Container( + decoration: BoxDecoration( + color: Colors.black.withOpacity(0), + ), + ), + ) + : null, + ].where((a) => a != null).toList(), + )), + ); + } +} diff --git a/lib/screens/fragments/templates/destination_view.dart b/lib/screens/fragments/templates/destination_view.dart new file mode 100644 index 0000000..1fef7bc --- /dev/null +++ b/lib/screens/fragments/templates/destination_view.dart @@ -0,0 +1,177 @@ +import 'package:digamobile/styles/constants.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:line_awesome_icons/line_awesome_icons.dart'; + +class DestinationView extends StatefulWidget { + DestinationView({Key key, this.destination}) : super(key: key); + final PageDestination destination; + + @override + _DestinationViewState createState() => _DestinationViewState(); +} + +class PageDestination { + final index; + final String title; + final IconData icon; + final IconData activeIcon; + final MaterialColor materialColor; + final Color materialColorLight; + + const PageDestination( + this.title, this.materialColor, this.icon, this.activeIcon, this.index, + {this.materialColorLight: Colors.white}); +} + +class _DestinationViewState extends State { + @override + Widget build(BuildContext context) { + return Navigator( + onGenerateRoute: (RouteSettings settings) { + return MaterialPageRoute( + settings: settings, + builder: (BuildContext context) { + switch (settings.name) { + case '/': + return RootPage(destination: widget.destination); + case '/list': + return ListPage(destination: widget.destination); + case '/text': + return TextPage(destination: widget.destination); + } + }, + ); + }, + ); + } +} + +class RootPage extends StatelessWidget { + const RootPage({Key key, this.destination}) : super(key: key); + + final PageDestination destination; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(destination.title), + backgroundColor: destination.materialColor, + ), + backgroundColor: destination.materialColor[50], + body: SizedBox.expand( + child: InkWell( + onTap: () { + Navigator.pushNamed(context, "/list"); + }, + ), + ), + ); + } +} + +class ListPage extends StatelessWidget { + const ListPage({Key key, this.destination}) : super(key: key); + + final PageDestination destination; + + @override + Widget build(BuildContext context) { + const List shades = [ + 50, + 100, + 200, + 300, + 400, + 500, + 600, + 700, + 800, + 900 + ]; + + return Scaffold( + appBar: AppBar( + title: Text(destination.title), + backgroundColor: destination.materialColor, + ), + backgroundColor: destination.materialColor[50], + body: SizedBox.expand( + child: ListView.builder( + itemCount: shades.length, + itemBuilder: (BuildContext context, int index) { + return SizedBox( + height: 128, + child: Card( + color: + destination.materialColor[shades[index]].withOpacity(0.25), + child: InkWell( + onTap: () { + Navigator.pushNamed(context, "/text"); + }, + child: Center( + child: Text('Item $index', + style: Theme.of(context).primaryTextTheme.display1), + ), + ), + ), + ); + }, + ), + ), + ); + } +} + +class TextPage extends StatefulWidget { + const TextPage({Key key, this.destination}) : super(key: key); + + final PageDestination destination; + + @override + _TextPageState createState() => _TextPageState(); +} + +class _TextPageState extends State { + TextEditingController _textController; + + @override + void initState() { + super.initState(); + _textController = TextEditingController( + text: 'sample text: ${widget.destination.title}', + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(widget.destination.title), + backgroundColor: widget.destination.materialColor, + ), + backgroundColor: widget.destination.materialColor[50], + body: Container( + padding: const EdgeInsets.all(32.0), + alignment: Alignment.center, + child: TextField(controller: _textController), + ), + ); + } + + @override + void dispose() { + _textController.dispose(); + super.dispose(); + } +} + +//The destination information for the bottom navigation +List allDestinations = [ + PageDestination('Home', Colors.blue, CupertinoIcons.home, Icons.home, + Constants.HOME_MAIN_PAGE), + PageDestination('Appointments', Colors.blue, CupertinoIcons.book, + CupertinoIcons.book_solid, Constants.APPOINTMENTS_MAIN_PAGE), +]; diff --git a/lib/screens/home_page.dart b/lib/screens/home_page.dart index acf5188..502623f 100644 --- a/lib/screens/home_page.dart +++ b/lib/screens/home_page.dart @@ -43,4 +43,4 @@ class HomePage extends StatelessWidget { ), floatingActionButton: new IncreaseCountButton()); } -} \ No newline at end of file +} diff --git a/lib/styles/constants.dart b/lib/styles/constants.dart new file mode 100644 index 0000000..fc4ac72 --- /dev/null +++ b/lib/styles/constants.dart @@ -0,0 +1,5 @@ +class Constants { + ///Main Route Pages + static const HOME_MAIN_PAGE = 0; + static const APPOINTMENTS_MAIN_PAGE = 1; +} diff --git a/pubspec.lock b/pubspec.lock index 09be7ec..188cd45 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -64,6 +64,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.1.3" + custom_navigator: + dependency: "direct main" + description: + name: custom_navigator + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.0" + dash_chat: + dependency: "direct main" + description: + name: dash_chat + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.16" firebase: dependency: transitive description: @@ -118,6 +132,20 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_inner_drawer: + dependency: "direct main" + description: + name: flutter_inner_drawer + url: "https://pub.dartlang.org" + source: hosted + version: "0.5.4" + flutter_parsed_text: + dependency: transitive + description: + name: flutter_parsed_text + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.3" flutter_redux: dependency: "direct main" description: @@ -135,6 +163,13 @@ packages: description: flutter source: sdk version: "0.0.0" + font_awesome_flutter: + dependency: "direct main" + description: + name: font_awesome_flutter + url: "https://pub.dartlang.org" + source: hosted + version: "8.7.0" google_sign_in: dependency: "direct main" description: @@ -177,6 +212,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.4" + intl: + dependency: transitive + description: + name: intl + url: "https://pub.dartlang.org" + source: hosted + version: "0.16.1" js: dependency: transitive description: @@ -184,6 +226,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.6.1+1" + line_awesome_icons: + dependency: "direct main" + description: + name: line_awesome_icons + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.4+2" logging: dependency: transitive description: @@ -301,6 +350,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.2.14" + transparent_image: + dependency: transitive + description: + name: transparent_image + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" typed_data: dependency: transitive description: @@ -308,6 +364,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.6" + uuid: + dependency: transitive + description: + name: uuid + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.4" vector_math: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index a1740c5..3d5da4b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -24,9 +24,14 @@ dependencies: redux_logging: ^0.4.0 firebase_auth: 0.15.3 google_sign_in: ^4.1.1 + dash_chat: ^1.0.16 + custom_navigator: ^0.3.0 + flutter_inner_drawer: ^0.5.4 # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^0.1.2 + font_awesome_flutter: ^8.5.0 + line_awesome_icons: ^1.0.4+2 dependency_overrides: firebase_core: 0.4.4 @@ -34,30 +39,24 @@ dependency_overrides: dev_dependencies: flutter_test: sdk: flutter - # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec # The following section is specific to Flutter. flutter: - # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. uses-material-design: true - # To add assets to your application, add an assets section, like this: # assets: # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg - # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware. - # For details regarding adding assets from package dependencies, see # https://flutter.dev/assets-and-images/#from-packages - # To add custom fonts to your application, add a fonts section here, # in this "flutter" section. Each entry in this list should have a # "family" key with the font family name, and a "fonts" key with a From c96d767157231dd8e29cb0aeef0f0d1fc57f57be Mon Sep 17 00:00:00 2001 From: David-solly Date: Tue, 3 Mar 2020 00:35:39 +0000 Subject: [PATCH 07/10] Added routing for chat --- android/app/src/main/AndroidManifest.xml | 22 +-- android/settings_aar.gradle | 1 + lib/actions/messaging_actions.dart | 13 ++ lib/screens/app_base_screen.dart | 24 +-- lib/screens/authentication_service.dart | 4 +- lib/screens/fragments/chat_fragment.dart | 155 +++++++++++++++++- .../navigation_drawers/navigation_drawer.dart | 52 +----- lib/screens/home_page.dart | 111 +++++++++---- lib/styles/constants.dart | 9 + pubspec.lock | 21 +++ pubspec.yaml | 4 +- 11 files changed, 309 insertions(+), 107 deletions(-) create mode 100644 android/settings_aar.gradle create mode 100644 lib/actions/messaging_actions.dart diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index be4a01e..4c04832 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,21 +1,13 @@ - + - - + + + + @@ -23,8 +15,6 @@ - + diff --git a/android/settings_aar.gradle b/android/settings_aar.gradle new file mode 100644 index 0000000..e7b4def --- /dev/null +++ b/android/settings_aar.gradle @@ -0,0 +1 @@ +include ':app' diff --git a/lib/actions/messaging_actions.dart b/lib/actions/messaging_actions.dart new file mode 100644 index 0000000..08235f7 --- /dev/null +++ b/lib/actions/messaging_actions.dart @@ -0,0 +1,13 @@ +class AddMessage { + final payload; + + AddMessage(this.payload); +} + +class AddAllMessages { + final payload; + + AddAllMessages(this.payload); +} + +class DeleteAllMessages {} diff --git a/lib/screens/app_base_screen.dart b/lib/screens/app_base_screen.dart index 5c7db43..3f56def 100644 --- a/lib/screens/app_base_screen.dart +++ b/lib/screens/app_base_screen.dart @@ -9,8 +9,8 @@ import 'package:line_awesome_icons/line_awesome_icons.dart'; import 'home_page.dart'; class AppBase extends StatefulWidget { - AppBase({Key key}) : super(key: key); - + AppBase({Key key, this.isLoggedIn}) : super(key: key); + final isLoggedIn; @override _AppBaseState createState() => _AppBaseState(); } @@ -73,7 +73,7 @@ class _AppBaseState extends State with TickerProviderStateMixin { tapScaffoldEnabled: _tapScaffold, offset: IDOffset.horizontal(_offset), - swipe: !_swipe, + swipe: _swipe, boxShadow: _direction == InnerDrawerDirection.start && _animationType == InnerDrawerAnimation.linear ? [] @@ -81,7 +81,10 @@ class _AppBaseState extends State with TickerProviderStateMixin { colorTransition: currentColor, leftAnimationType: _animationType, rightAnimationType: InnerDrawerAnimation.linear, - leftChild: NavigationDrawer(dragUpdate: _dragUpdate), + leftChild: NavigationDrawer( + dragUpdate: _dragUpdate, + isSignedIn: widget.isLoggedIn, + ), //rightChild: MapFilterDrawer(), @@ -93,12 +96,9 @@ class _AppBaseState extends State with TickerProviderStateMixin { scaffold: Scaffold( floatingActionButton: FloatingActionButton.extended( onPressed: () {}, - label: Padding( - padding: const EdgeInsets.only(left: 8.0), - child: Text("Chat Assist"), - ), + label: Text("Appointment"), icon: Icon( - Icons.chat, + Icons.add, color: allDestinations[_index].materialColorLight, ), ), @@ -134,9 +134,9 @@ class _AppBaseState extends State with TickerProviderStateMixin { child: KeyedSubtree( key: _destinationKeys[destination.index], child: _index == 0 - ? HomePage( - "Welcome", - ) + ? HomePage("Welcome", () { + _dragUpdate = 1.0; + }) : DestinationView( destination: destination, ), diff --git a/lib/screens/authentication_service.dart b/lib/screens/authentication_service.dart index f43a254..8f551ad 100644 --- a/lib/screens/authentication_service.dart +++ b/lib/screens/authentication_service.dart @@ -18,7 +18,9 @@ class AuthenticationService extends StatelessWidget { stream: FirebaseAuth.instance.onAuthStateChanged, builder: (context, snapshot) { if (snapshot.hasData) { - return AppBase(); + return AppBase( + isLoggedIn: true, + ); } else { return LoginScreen(); } diff --git a/lib/screens/fragments/chat_fragment.dart b/lib/screens/fragments/chat_fragment.dart index 44a534b..b2d8a6c 100644 --- a/lib/screens/fragments/chat_fragment.dart +++ b/lib/screens/fragments/chat_fragment.dart @@ -1,9 +1,17 @@ import 'dart:async'; +import 'dart:io'; import 'package:dash_chat/dash_chat.dart'; +import 'package:digamobile/screens/fragments/templates/destination_view.dart'; import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:simple_permissions/simple_permissions.dart'; class ChatFragment extends StatefulWidget { + final PageDestination destination; + + const ChatFragment({Key key, this.destination}) : super(key: key); @override _ChatFragmentState createState() => _ChatFragmentState(); } @@ -11,6 +19,23 @@ class ChatFragment extends StatefulWidget { class _ChatFragmentState extends State { final GlobalKey _chatViewKey = GlobalKey(); + File _image; + + Future getImage() async { + PermissionStatus permissionResult = + await SimplePermissions.requestPermission( + Permission.WriteExternalStorage); + if (permissionResult == PermissionStatus.authorized) { + // code of read or write file in external storage (SD card) + + var image = await ImagePicker.pickImage(source: ImageSource.gallery); + + setState(() { + _image = image; + }); + } + } + final ChatUser user = ChatUser( name: "Fayeed", uid: "123456789", @@ -63,7 +88,10 @@ class _ChatFragmentState extends State { Timer(Duration(milliseconds: 300), () { if (i < 6) { setState(() { - messages = [...messages, m[i]]; + //messages = [...messages, m[i]]; + messages = [] + ..addAll(messages) + ..add(m[i]); }); i++; } @@ -91,7 +119,10 @@ class _ChatFragmentState extends State { // ); // }); setState(() { - messages = [...messages, message]; + //messages = [...messages, message]; + messages = [] + ..addAll(messages) + ..add(message); print(messages.length); }); @@ -107,7 +138,123 @@ class _ChatFragmentState extends State { @override Widget build(BuildContext context) { - // TODO: implement build - throw UnimplementedError(); + return Scaffold( + appBar: CupertinoNavigationBar(), + body: DashChat( + height: MediaQuery.of(context).size.height - 60.0, + key: _chatViewKey, + inverted: false, + onSend: onSend, + user: user, + inputDecoration: + InputDecoration.collapsed(hintText: "Add message here..."), + dateFormat: DateFormat('yyyy-MMM-dd'), + timeFormat: DateFormat('HH:mm'), + messages: messages, + showUserAvatar: true, + showAvatarForEveryMessage: false, + scrollToBottom: true, + // inputFooterBuilder: () { + // return Column( + // children: [ + // Text('asd'), + // Text('asd'), + // Text('asd'), + // Text('asd'), + // Text('asd'), + // Text('asd'), + // ], + // ); + // }, + onPressAvatar: (ChatUser user) { + print("OnPressAvatar: ${user.name}"); + }, + onLongPressAvatar: (ChatUser user) { + print("OnLongPressAvatar: ${user.name}"); + }, + inputMaxLines: 5, + alwaysShowSend: true, + inputTextStyle: TextStyle(fontSize: 16.0), + inputContainerStyle: BoxDecoration( + border: Border.all(width: 0.0), + color: Colors.white, + ), + onQuickReply: (Reply reply) { + setState(() { + messages.add(ChatMessage( + text: reply.value, createdAt: DateTime.now(), user: user)); + + messages = []..addAll(messages); + }); + + Timer(Duration(milliseconds: 300), () { + _chatViewKey.currentState.scrollController + ..animateTo( + _chatViewKey + .currentState.scrollController.position.maxScrollExtent, + curve: Curves.easeOut, + duration: const Duration(milliseconds: 300), + ); + + if (i == 0) { + systemMessage(); + Timer(Duration(milliseconds: 600), () { + systemMessage(); + }); + } else { + systemMessage(); + } + }); + }, + onLoadEarlier: () { + print("laoding..."); + }, + shouldShowLoadEarlier: false, + showTraillingBeforeSend: true, + trailing: [ + IconButton( + icon: Icon(Icons.photo), + onPressed: () async { + File result = await ImagePicker.pickImage( + source: ImageSource.gallery, + maxHeight: 400, + maxWidth: 400, + ); + + // if (result != null) { + // final StorageReference storageRef = + // FirebaseStorage.instance.ref().child("chat_images"); + + // StorageUploadTask uploadTask = storageRef.putFile( + // result, + // StorageMetadata( + // contentType: 'image/jpg', + // ), + // ); + // StorageTaskSnapshot download = + // await uploadTask.onComplete; + + // String url = await download.ref.getDownloadURL(); + + // ChatMessage message = + // ChatMessage(text: "", user: user, image: url); + + // var documentReference = Firestore.instance + // .collection('messages') + // .document( + // DateTime.now().millisecondsSinceEpoch.toString()); + + // Firestore.instance.runTransaction((transaction) async { + // await transaction.set( + // documentReference, + // message.toJson(), + // ); + // }); + // } + }, + ) + ], + ), + ); } } diff --git a/lib/screens/fragments/navigation_drawers/navigation_drawer.dart b/lib/screens/fragments/navigation_drawers/navigation_drawer.dart index dea4163..f4da4bc 100644 --- a/lib/screens/fragments/navigation_drawers/navigation_drawer.dart +++ b/lib/screens/fragments/navigation_drawers/navigation_drawer.dart @@ -6,10 +6,10 @@ import 'package:line_awesome_icons/line_awesome_icons.dart'; import '../../../auth_service.dart'; class NavigationDrawer extends StatelessWidget { - NavigationDrawer({Key key, this.dragUpdate: 0}) : super(key: key); + NavigationDrawer({Key key, this.dragUpdate: 0, this.isSignedIn: false}) + : super(key: key); final double dragUpdate; - final availableSos = false; - final isSignedIn = false; + final isSignedIn; final hasRated = false; @override Widget build(BuildContext context) { @@ -91,45 +91,7 @@ class NavigationDrawer extends StatelessWidget { ))), ), Padding( - padding: const EdgeInsets.only(bottom: 24.0), - child: Container( - height: 1, - color: Colors.grey, - ), - ), - Material( - color: availableSos - ? Colors.red[800] - : Colors.red.shade900.withAlpha(150), - child: InkWell( - onTap: () => print("Sos"), - child: ListTile( - title: Text( - "S.O.S", - style: TextStyle( - color: availableSos - ? Colors.white - : Colors.grey.shade300, - fontSize: 14), - ), - trailing: availableSos - ? Icon( - Icons.adjust, - color: Colors.green[300], - ) - : Icon( - Icons.album, - color: Colors.red[700].withAlpha(150), - ), - leading: Icon( - LineAwesomeIcons.exclamation_triangle, - //FontAwesomeIcons.exclamationTriangle, - color: Colors.white, - size: 22, - ))), - ), - Padding( - padding: const EdgeInsets.only(top: 24.0), + padding: const EdgeInsets.only(top: 12.0), child: Container( height: 1, color: Colors.grey, @@ -216,14 +178,14 @@ class NavigationDrawer extends StatelessWidget { onTap: () => AuthService().signOut(), child: ListTile( title: Text( - "Logout", + "Sign Out", style: TextStyle( - color: Colors.grey, + color: Colors.white, fontSize: 16), ), leading: Icon( Icons.exit_to_app, - color: Colors.grey, + color: Colors.white, size: 22, ))), ), diff --git a/lib/screens/home_page.dart b/lib/screens/home_page.dart index 502623f..fc22e19 100644 --- a/lib/screens/home_page.dart +++ b/lib/screens/home_page.dart @@ -1,46 +1,101 @@ import 'package:digamobile/auth_service.dart'; import 'package:digamobile/containers/counter/counter.dart'; import 'package:digamobile/containers/counter/increase_counter.dart'; +import 'package:digamobile/screens/fragments/chat_fragment.dart'; +import 'package:digamobile/screens/fragments/templates/destination_view.dart'; +import 'package:digamobile/styles/constants.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; class HomePage extends StatelessWidget { final String title; + //Call back to pass menu click event to the app base to open the app drawer + final Function() MenuClicked; + final PageDestination destination; - HomePage(this.title); + HomePage(this.title, this.MenuClicked, {this.destination}); + + @override + Widget build(BuildContext context) { + return Navigator( + onGenerateRoute: (RouteSettings settings) { + return MaterialPageRoute( + settings: settings, + builder: (BuildContext context) { + switch (settings.name) { + case ConstantsRoutes.HOME_ROOT_PAGE: + return _HomeScreen( + destination: destination, + title: title, + ); + case ConstantsRoutes.HOME_CHAT_PAGE: + return ChatFragment(destination: destination); + } + }, + ); + }, + ); + } +} + +class _HomeScreen extends StatelessWidget { + const _HomeScreen({Key key, this.title, this.menuClicked, this.destination}) + : super(key: key); + final String title; + //Call back to pass menu click event to the app base to open the app drawer + final Function() menuClicked; + final PageDestination destination; @override Widget build(BuildContext context) { return new Scaffold( - backgroundColor: Colors.grey[50], - appBar: new AppBar( - title: new Text(this.title), - backgroundColor: Colors.white, - elevation: 0.0, + backgroundColor: Colors.grey[50], + appBar: new AppBar( + centerTitle: true, + title: new Text( + this.title, + style: TextStyle(color: Colors.grey.shade800, fontSize: 14), ), - body: new Container( - child: new Center( - child: new Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text('You are logged in'), - SizedBox(height: 10.0), - RaisedButton( - onPressed: () { - AuthService().signOut(); - }, - child: Center( - child: Text('Sign Out'), - ), - color: Colors.red, - ), - new Text( - 'You have pushed the button this many times:', - ), - new Counter(), - ], + backgroundColor: Colors.white, + elevation: 0.0, + leading: IconButton( + icon: Icon( + Icons.menu, + color: Colors.grey.shade900, ), + onPressed: () {}), + ), + body: new Container( + child: new Center( + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('You are logged in'), + SizedBox(height: 10.0), + RaisedButton( + onPressed: () { + AuthService().signOut(); + }, + child: Center( + child: Text('Sign Out'), + ), + color: Colors.red, + ), + new Text( + 'You have pushed the button this many times:', + ), + new Counter(), + ], ), ), - floatingActionButton: new IncreaseCountButton()); + ), + //floatingActionButton: new IncreaseCountButton()); + floatingActionButton: FloatingActionButton( + onPressed: () => + Navigator.of(context).pushNamed(ConstantsRoutes.HOME_CHAT_PAGE), + child: Icon(Icons.chat), + ), + resizeToAvoidBottomInset: true, + ); } } diff --git a/lib/styles/constants.dart b/lib/styles/constants.dart index fc4ac72..e47e323 100644 --- a/lib/styles/constants.dart +++ b/lib/styles/constants.dart @@ -3,3 +3,12 @@ class Constants { static const HOME_MAIN_PAGE = 0; static const APPOINTMENTS_MAIN_PAGE = 1; } + +///Provides const values used in routing the app from page to page +class ConstantsRoutes { + ///'/' : Reperesents the root page of the [HomePage] + static const HOME_ROOT_PAGE = "/"; + + ///'/chat' : Represents the [ChatFragment] page - from the [HomePage] base + static const HOME_CHAT_PAGE = "/chat"; +} diff --git a/pubspec.lock b/pubspec.lock index 188cd45..66abab1 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -146,6 +146,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.3" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.6" flutter_redux: dependency: "direct main" description: @@ -212,6 +219,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.4" + image_picker: + dependency: "direct main" + description: + name: image_picker + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.3+4" intl: dependency: transitive description: @@ -303,6 +317,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.4.0" + simple_permissions: + dependency: "direct main" + description: + name: simple_permissions + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.9" sky_engine: dependency: transitive description: flutter diff --git a/pubspec.yaml b/pubspec.yaml index 3d5da4b..3ceaec2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -14,7 +14,7 @@ description: A new Flutter project. version: 1.0.0+1 environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.6.0 <3.0.0" dependencies: flutter: @@ -32,6 +32,8 @@ dependencies: cupertino_icons: ^0.1.2 font_awesome_flutter: ^8.5.0 line_awesome_icons: ^1.0.4+2 + image_picker: ^0.6.3+4 + simple_permissions: ^0.1.9 dependency_overrides: firebase_core: 0.4.4 From 32fa09e4264b64b0c7b5a50472efcb090978bc13 Mon Sep 17 00:00:00 2001 From: David-solly Date: Tue, 3 Mar 2020 02:09:24 +0000 Subject: [PATCH 08/10] Added chat ui --- .../gradle/wrapper/gradle-wrapper.properties | 1 + lib/screens/app_base_screen.dart | 54 +++- lib/screens/fragments/chat_fragment.dart | 270 +++++++++--------- lib/screens/home_page.dart | 36 ++- pubspec.lock | 7 - pubspec.yaml | 1 - 6 files changed, 208 insertions(+), 161 deletions(-) diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index d23770e..779f777 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -4,3 +4,4 @@ distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip + diff --git a/lib/screens/app_base_screen.dart b/lib/screens/app_base_screen.dart index 3f56def..dc591e8 100644 --- a/lib/screens/app_base_screen.dart +++ b/lib/screens/app_base_screen.dart @@ -22,9 +22,13 @@ class _AppBaseState extends State with TickerProviderStateMixin { bool _onTapToClose = false; bool _swipe = true; bool _tapScaffold = true; + bool _isChatEnabled = true; InnerDrawerAnimation _animationType = InnerDrawerAnimation.static; double _offset = 0.4; + AnimationController _controller; + Animation _drawerState; + double _dragUpdate = 0; int _index = 0; InnerDrawerDirection _direction = InnerDrawerDirection.start; @@ -44,7 +48,22 @@ class _AppBaseState extends State with TickerProviderStateMixin { @override void initState() { print("@@@@----MAIN____APPP____INIT___STATE"); - + _controller = + AnimationController(vsync: this, duration: Duration(milliseconds: 500)); + _drawerState = Tween(begin: 0.0, end: 1.0).animate(_controller); + _controller.addListener(() { + print("animating ${_drawerState.value}"); + + print("Clicked"); + _direction = InnerDrawerDirection.start; + setState(() => _dragUpdate = _drawerState.value); + }); + _drawerState.addListener(() { + setState(() { + print("Clicked"); + this._dragUpdate = _drawerState.value; + }); + }); _faders = allDestinations.map((PageDestination destination) { return AnimationController( @@ -94,14 +113,16 @@ class _AppBaseState extends State with TickerProviderStateMixin { }, //innerDrawerCallback: (a) => print(a), scaffold: Scaffold( - floatingActionButton: FloatingActionButton.extended( - onPressed: () {}, - label: Text("Appointment"), - icon: Icon( - Icons.add, - color: allDestinations[_index].materialColorLight, - ), - ), + floatingActionButton: _isChatEnabled + ? null + : FloatingActionButton.extended( + onPressed: () {}, + label: Text("Appointment"), + icon: Icon( + Icons.add, + color: allDestinations[_index].materialColorLight, + ), + ), floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked, extendBody: false, @@ -134,9 +155,18 @@ class _AppBaseState extends State with TickerProviderStateMixin { child: KeyedSubtree( key: _destinationKeys[destination.index], child: _index == 0 - ? HomePage("Welcome", () { - _dragUpdate = 1.0; - }) + ? HomePage( + "Welcome", + menuClicked: () { + print("clicked in base"); + _controller.status == AnimationStatus.completed || + _controller.status == + AnimationStatus.reverse + ? _controller.forward() + : _controller.reverse(); + _controller.forward(); + }, + ) : DestinationView( destination: destination, ), diff --git a/lib/screens/fragments/chat_fragment.dart b/lib/screens/fragments/chat_fragment.dart index b2d8a6c..cd6997b 100644 --- a/lib/screens/fragments/chat_fragment.dart +++ b/lib/screens/fragments/chat_fragment.dart @@ -6,12 +6,14 @@ import 'package:digamobile/screens/fragments/templates/destination_view.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; -import 'package:simple_permissions/simple_permissions.dart'; class ChatFragment extends StatefulWidget { final PageDestination destination; - const ChatFragment({Key key, this.destination}) : super(key: key); + const ChatFragment({ + Key key, + this.destination, + }) : super(key: key); @override _ChatFragmentState createState() => _ChatFragmentState(); } @@ -22,18 +24,18 @@ class _ChatFragmentState extends State { File _image; Future getImage() async { - PermissionStatus permissionResult = - await SimplePermissions.requestPermission( - Permission.WriteExternalStorage); - if (permissionResult == PermissionStatus.authorized) { - // code of read or write file in external storage (SD card) + // PermissionStatus permissionResult = + // await SimplePermissions.requestPermission( + // Permission.WriteExternalStorage); + // if (permissionResult == PermissionStatus.authorized) { + // // code of read or write file in external storage (SD card) - var image = await ImagePicker.pickImage(source: ImageSource.gallery); + var image = await ImagePicker.pickImage(source: ImageSource.gallery); - setState(() { - _image = image; - }); - } + setState(() { + _image = image; + }); + //} } final ChatUser user = ChatUser( @@ -66,21 +68,6 @@ class _ChatFragmentState extends State { ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), ]); } @@ -139,120 +126,139 @@ class _ChatFragmentState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: CupertinoNavigationBar(), - body: DashChat( - height: MediaQuery.of(context).size.height - 60.0, - key: _chatViewKey, - inverted: false, - onSend: onSend, - user: user, - inputDecoration: - InputDecoration.collapsed(hintText: "Add message here..."), - dateFormat: DateFormat('yyyy-MMM-dd'), - timeFormat: DateFormat('HH:mm'), - messages: messages, - showUserAvatar: true, - showAvatarForEveryMessage: false, - scrollToBottom: true, - // inputFooterBuilder: () { - // return Column( - // children: [ - // Text('asd'), - // Text('asd'), - // Text('asd'), - // Text('asd'), - // Text('asd'), - // Text('asd'), - // ], - // ); - // }, - onPressAvatar: (ChatUser user) { - print("OnPressAvatar: ${user.name}"); - }, - onLongPressAvatar: (ChatUser user) { - print("OnLongPressAvatar: ${user.name}"); - }, - inputMaxLines: 5, - alwaysShowSend: true, - inputTextStyle: TextStyle(fontSize: 16.0), - inputContainerStyle: BoxDecoration( - border: Border.all(width: 0.0), - color: Colors.white, - ), - onQuickReply: (Reply reply) { - setState(() { - messages.add(ChatMessage( - text: reply.value, createdAt: DateTime.now(), user: user)); + extendBody: false, + appBar: CupertinoNavigationBar( + automaticallyImplyMiddle: true, + automaticallyImplyLeading: true, + leading: IconButton( + icon: Icon(CupertinoIcons.back), + onPressed: () { + if (Navigator.of(context).canPop()) Navigator.of(context).pop(); + }), + ), + body: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Flexible( + flex: 1, + child: DashChat( + height: MediaQuery.of(context).size.height - 120.0, + key: _chatViewKey, + inverted: false, + onSend: onSend, + user: user, - messages = []..addAll(messages); - }); + inputDecoration: InputDecoration(hintText: "Add message here..."), + dateFormat: DateFormat('yyyy-MMM-dd'), + timeFormat: DateFormat('HH:mm'), + messages: messages, + showUserAvatar: true, + showAvatarForEveryMessage: false, + scrollToBottom: true, + // inputFooterBuilder: () { + // return Column( + // children: [ + // Text('asd'), + // Text('asd'), + // Text('asd'), + // Text('asd'), + // Text('asd'), + // Text('asd'), + // ], + // ); + // }, + onPressAvatar: (ChatUser user) { + print("OnPressAvatar: ${user.name}"); + }, + onLongPressAvatar: (ChatUser user) { + print("OnLongPressAvatar: ${user.name}"); + }, + inputMaxLines: 5, + alwaysShowSend: true, + inputTextStyle: TextStyle(fontSize: 16.0), + inputContainerStyle: BoxDecoration( + border: Border.all(width: 0.0), + color: Colors.white, + ), + onQuickReply: (Reply reply) { + setState(() { + messages.add(ChatMessage( + text: reply.value, + createdAt: DateTime.now(), + user: user)); - Timer(Duration(milliseconds: 300), () { - _chatViewKey.currentState.scrollController - ..animateTo( - _chatViewKey - .currentState.scrollController.position.maxScrollExtent, - curve: Curves.easeOut, - duration: const Duration(milliseconds: 300), - ); + messages = []..addAll(messages); + }); - if (i == 0) { - systemMessage(); - Timer(Duration(milliseconds: 600), () { - systemMessage(); - }); - } else { - systemMessage(); - } - }); - }, - onLoadEarlier: () { - print("laoding..."); - }, - shouldShowLoadEarlier: false, - showTraillingBeforeSend: true, - trailing: [ - IconButton( - icon: Icon(Icons.photo), - onPressed: () async { - File result = await ImagePicker.pickImage( - source: ImageSource.gallery, - maxHeight: 400, - maxWidth: 400, - ); + Timer(Duration(milliseconds: 300), () { + _chatViewKey.currentState.scrollController + ..animateTo( + _chatViewKey.currentState.scrollController.position + .maxScrollExtent, + curve: Curves.easeOut, + duration: const Duration(milliseconds: 300), + ); - // if (result != null) { - // final StorageReference storageRef = - // FirebaseStorage.instance.ref().child("chat_images"); + if (i == 0) { + systemMessage(); + Timer(Duration(milliseconds: 600), () { + systemMessage(); + }); + } else { + systemMessage(); + } + }); + }, + onLoadEarlier: () { + print("laoding..."); + }, + shouldShowLoadEarlier: false, + showTraillingBeforeSend: true, + trailing: [ + IconButton( + icon: Icon(Icons.photo), + onPressed: () async { + File result = await ImagePicker.pickImage( + source: ImageSource.gallery, + maxHeight: 400, + maxWidth: 400, + ); - // StorageUploadTask uploadTask = storageRef.putFile( - // result, - // StorageMetadata( - // contentType: 'image/jpg', - // ), - // ); - // StorageTaskSnapshot download = - // await uploadTask.onComplete; + // if (result != null) { + // final StorageReference storageRef = + // FirebaseStorage.instance.ref().child("chat_images"); + + // StorageUploadTask uploadTask = storageRef.putFile( + // result, + // StorageMetadata( + // contentType: 'image/jpg', + // ), + // ); + // StorageTaskSnapshot download = + // await uploadTask.onComplete; - // String url = await download.ref.getDownloadURL(); + // String url = await download.ref.getDownloadURL(); - // ChatMessage message = - // ChatMessage(text: "", user: user, image: url); + // ChatMessage message = + // ChatMessage(text: "", user: user, image: url); - // var documentReference = Firestore.instance - // .collection('messages') - // .document( - // DateTime.now().millisecondsSinceEpoch.toString()); + // var documentReference = Firestore.instance + // .collection('messages') + // .document( + // DateTime.now().millisecondsSinceEpoch.toString()); - // Firestore.instance.runTransaction((transaction) async { - // await transaction.set( - // documentReference, - // message.toJson(), - // ); - // }); - // } - }, - ) + // Firestore.instance.runTransaction((transaction) async { + // await transaction.set( + // documentReference, + // message.toJson(), + // ); + // }); + // } + }, + ) + ], + ), + ), ], ), ); diff --git a/lib/screens/home_page.dart b/lib/screens/home_page.dart index fc22e19..ffc6c9d 100644 --- a/lib/screens/home_page.dart +++ b/lib/screens/home_page.dart @@ -10,10 +10,14 @@ import 'package:flutter/material.dart'; class HomePage extends StatelessWidget { final String title; //Call back to pass menu click event to the app base to open the app drawer - final Function() MenuClicked; + final VoidCallback menuClicked; final PageDestination destination; - HomePage(this.title, this.MenuClicked, {this.destination}); + HomePage( + this.title, { + this.menuClicked, + this.destination, + }); @override Widget build(BuildContext context) { @@ -27,9 +31,15 @@ class HomePage extends StatelessWidget { return _HomeScreen( destination: destination, title: title, + menuClicked: () { + print("Clicked in home"); + this.menuClicked.call(); + }, ); case ConstantsRoutes.HOME_CHAT_PAGE: - return ChatFragment(destination: destination); + return ChatFragment( + destination: destination, + ); } }, ); @@ -39,11 +49,16 @@ class HomePage extends StatelessWidget { } class _HomeScreen extends StatelessWidget { - const _HomeScreen({Key key, this.title, this.menuClicked, this.destination}) - : super(key: key); + const _HomeScreen({ + Key key, + this.title, + this.menuClicked, + this.destination, + }) : super(key: key); final String title; //Call back to pass menu click event to the app base to open the app drawer - final Function() menuClicked; + final VoidCallback menuClicked; + final PageDestination destination; @override @@ -63,7 +78,9 @@ class _HomeScreen extends StatelessWidget { Icons.menu, color: Colors.grey.shade900, ), - onPressed: () {}), + onPressed: () { + this.menuClicked.call(); + }), ), body: new Container( child: new Center( @@ -91,8 +108,9 @@ class _HomeScreen extends StatelessWidget { ), //floatingActionButton: new IncreaseCountButton()); floatingActionButton: FloatingActionButton( - onPressed: () => - Navigator.of(context).pushNamed(ConstantsRoutes.HOME_CHAT_PAGE), + onPressed: () { + Navigator.of(context).pushNamed(ConstantsRoutes.HOME_CHAT_PAGE); + }, child: Icon(Icons.chat), ), resizeToAvoidBottomInset: true, diff --git a/pubspec.lock b/pubspec.lock index 66abab1..07f1cc7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -317,13 +317,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.4.0" - simple_permissions: - dependency: "direct main" - description: - name: simple_permissions - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.9" sky_engine: dependency: transitive description: flutter diff --git a/pubspec.yaml b/pubspec.yaml index 3ceaec2..2396bd8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -33,7 +33,6 @@ dependencies: font_awesome_flutter: ^8.5.0 line_awesome_icons: ^1.0.4+2 image_picker: ^0.6.3+4 - simple_permissions: ^0.1.9 dependency_overrides: firebase_core: 0.4.4 From e6ccfd8d753b613aa111537a7780858c67663eb2 Mon Sep 17 00:00:00 2001 From: David-solly Date: Tue, 3 Mar 2020 16:07:49 +0000 Subject: [PATCH 09/10] added snatchbot view --- lib/screens/fragments/chat_fragment.dart | 38 ++++++++--- .../navigation_drawers/navigation_drawer.dart | 2 - lib/services/chatbot_service_config.dart | 63 +++++++++++++++++++ pubspec.lock | 9 ++- pubspec.yaml | 2 + 5 files changed, 103 insertions(+), 11 deletions(-) create mode 100644 lib/services/chatbot_service_config.dart diff --git a/lib/screens/fragments/chat_fragment.dart b/lib/screens/fragments/chat_fragment.dart index cd6997b..a2968f1 100644 --- a/lib/screens/fragments/chat_fragment.dart +++ b/lib/screens/fragments/chat_fragment.dart @@ -1,6 +1,8 @@ import 'dart:async'; import 'dart:io'; - +import 'package:digamobile/services/chatbot_service_config.dart'; +import 'package:flutter_webview_plugin/flutter_webview_plugin.dart'; +import 'package:http/http.dart' as http; import 'package:dash_chat/dash_chat.dart'; import 'package:digamobile/screens/fragments/templates/destination_view.dart'; import 'package:flutter/cupertino.dart'; @@ -38,6 +40,8 @@ class _ChatFragmentState extends State { //} } + ChatbotServiceConfig _chatConfig; + final ChatUser user = ChatUser( name: "Fayeed", uid: "123456789", @@ -56,9 +60,11 @@ class _ChatFragmentState extends State { var i = 0; @override - void initState() { + Future initState() { super.initState(); + _chatConfig = ChatbotServiceConfig( + 'https://account.snatchbot.me/channels/api/api/id94441/appcom.moozenhq.digamobile/apsF58DCEC4F87FBF5BFADE9F5D56F91'); messages.addAll([ ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), @@ -74,12 +80,13 @@ class _ChatFragmentState extends State { void systemMessage() { Timer(Duration(milliseconds: 300), () { if (i < 6) { - setState(() { - //messages = [...messages, m[i]]; - messages = [] - ..addAll(messages) - ..add(m[i]); - }); + if (mounted) if (m.length > i) + setState(() { + messages = [...messages, m[i]]; + // messages = [] + // ..addAll(messages) + // ..add(m[i]); + }); i++; } Timer(Duration(milliseconds: 300), () { @@ -95,6 +102,7 @@ class _ChatFragmentState extends State { void onSend(ChatMessage message) { print(message.toJson()); + _chatConfig.sendMessage(message); // var documentReference = Firestore.instance // .collection('messages') // .document(DateTime.now().millisecondsSinceEpoch.toString()); @@ -125,6 +133,18 @@ class _ChatFragmentState extends State { @override Widget build(BuildContext context) { + return new WebviewScaffold( + url: + "https://webchat.snatchbot.me/e30deda7335903ce072120872201193e4e9dac8004f8f2c770a6e3cb297bf8de", + appBar: new AppBar( + title: const Text('Diga Assistant'), + ), + withZoom: true, + withLocalStorage: true, + hidden: true, + initialChild: + Center(child: Container(child: CircularProgressIndicator())), + ); return Scaffold( extendBody: false, appBar: CupertinoNavigationBar( @@ -133,6 +153,8 @@ class _ChatFragmentState extends State { leading: IconButton( icon: Icon(CupertinoIcons.back), onPressed: () { + ///Dispose of the message streams and sinks as they are no longer needed + _chatConfig.dispose(); if (Navigator.of(context).canPop()) Navigator.of(context).pop(); }), ), diff --git a/lib/screens/fragments/navigation_drawers/navigation_drawer.dart b/lib/screens/fragments/navigation_drawers/navigation_drawer.dart index f4da4bc..0f071f8 100644 --- a/lib/screens/fragments/navigation_drawers/navigation_drawer.dart +++ b/lib/screens/fragments/navigation_drawers/navigation_drawer.dart @@ -22,8 +22,6 @@ class NavigationDrawer extends StatelessWidget { gradient: LinearGradient( begin: Alignment.topRight, end: Alignment.bottomLeft, - // Add one stop for each color. Stops should increase from 0 to 1 - //stops: [0.1, 0.5,0.5, 0.7, 0.9], colors: [ ColorTween( begin: Colors.blueAccent, diff --git a/lib/services/chatbot_service_config.dart b/lib/services/chatbot_service_config.dart new file mode 100644 index 0000000..a90cc22 --- /dev/null +++ b/lib/services/chatbot_service_config.dart @@ -0,0 +1,63 @@ +import 'dart:async'; +import 'dart:convert'; + +import 'package:http/http.dart' as http; + +import 'package:dash_chat/dash_chat.dart'; + +class ChatbotServiceConfig { + ChatbotServiceConfig(this.endPointUrl) { + if (client == null) client = http.Client(); + } + //api endpoint url, should be passed into the build proccess on the final build + //for now, will be hard coded. + final endPointUrl; + http.Client client; + + ///[StreamController] Controls the stream and Sink for message api + ///Set to broadcast so the messages don't decay on first emmit + StreamController _apiStreamController = StreamController.broadcast(); + + ///[chatBotMessageStream] is a [Stream]that will be subscribed to by any listeners + ///emmits messages from this api that are passed into the internal [StreamSink] + Stream get chatBotMessageStream => _apiStreamController.stream; + + ///[_internalMessageStreamSink] is the internal [StreamSink] + ///that is used to pass data to all listeners + StreamSink get _internalMessageStreamSink => _apiStreamController.sink; + + sendMessage(ChatMessage message, + {String url: + 'https://account.snatchbot.me/channels/api/api/id94441/appcom.moozenhq.digamobile/apsF58DCEC4F87FBF5BFADE9F5D56F91'}) async { + if (message.text != null) + try { + if (client == null) client = http.Client(); + + var uriResponse = await client.post(url, body: { + 'message': '${message.text}', + 'user_id': 'nedle', + "first_name": "Heckt" + }).then((value) async { + Map botMessage; + print(value.headers); + print(value.body); + + if (value.body != null) { + botMessage = jsonDecode(value.body); + print(botMessage); + } + }); + } catch (e) { + print("@@@error decoding:$e"); + } + } + + ///must call when done to prevent memory leaks + dispose() { + _apiStreamController.close(); + _internalMessageStreamSink.close(); + + ///close the connection to the http client chatbot api + client.close(); + } +} diff --git a/pubspec.lock b/pubspec.lock index 07f1cc7..163c306 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -170,6 +170,13 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_webview_plugin: + dependency: "direct main" + description: + name: flutter_webview_plugin + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.10+1" font_awesome_flutter: dependency: "direct main" description: @@ -199,7 +206,7 @@ packages: source: hosted version: "0.8.3+2" http: - dependency: transitive + dependency: "direct main" description: name: http url: "https://pub.dartlang.org" diff --git a/pubspec.yaml b/pubspec.yaml index 2396bd8..50ffb6e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -33,6 +33,8 @@ dependencies: font_awesome_flutter: ^8.5.0 line_awesome_icons: ^1.0.4+2 image_picker: ^0.6.3+4 + http: ^0.12.0+4 + flutter_webview_plugin: ^0.3.10+1 dependency_overrides: firebase_core: 0.4.4 From 261d367b58447c2344a144f70c87cadabe7a490a Mon Sep 17 00:00:00 2001 From: David-solly Date: Tue, 3 Mar 2020 16:12:50 +0000 Subject: [PATCH 10/10] cleaned chat view --- lib/screens/fragments/chat_fragment.dart | 249 ----------------------- 1 file changed, 249 deletions(-) diff --git a/lib/screens/fragments/chat_fragment.dart b/lib/screens/fragments/chat_fragment.dart index a2968f1..0ce32d8 100644 --- a/lib/screens/fragments/chat_fragment.dart +++ b/lib/screens/fragments/chat_fragment.dart @@ -1,13 +1,8 @@ import 'dart:async'; -import 'dart:io'; -import 'package:digamobile/services/chatbot_service_config.dart'; import 'package:flutter_webview_plugin/flutter_webview_plugin.dart'; -import 'package:http/http.dart' as http; -import 'package:dash_chat/dash_chat.dart'; import 'package:digamobile/screens/fragments/templates/destination_view.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:image_picker/image_picker.dart'; class ChatFragment extends StatefulWidget { final PageDestination destination; @@ -21,114 +16,9 @@ class ChatFragment extends StatefulWidget { } class _ChatFragmentState extends State { - final GlobalKey _chatViewKey = GlobalKey(); - - File _image; - - Future getImage() async { - // PermissionStatus permissionResult = - // await SimplePermissions.requestPermission( - // Permission.WriteExternalStorage); - // if (permissionResult == PermissionStatus.authorized) { - // // code of read or write file in external storage (SD card) - - var image = await ImagePicker.pickImage(source: ImageSource.gallery); - - setState(() { - _image = image; - }); - //} - } - - ChatbotServiceConfig _chatConfig; - - final ChatUser user = ChatUser( - name: "Fayeed", - uid: "123456789", - avatar: "https://www.wrappixel.com/ampleadmin/assets/images/users/4.jpg", - ); - - final ChatUser otherUser = ChatUser( - name: "Mrfatty", - uid: "25649654", - ); - - List messages = List(); - - var m = List(); - - var i = 0; - @override Future initState() { super.initState(); - - _chatConfig = ChatbotServiceConfig( - 'https://account.snatchbot.me/channels/api/api/id94441/appcom.moozenhq.digamobile/apsF58DCEC4F87FBF5BFADE9F5D56F91'); - messages.addAll([ - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ChatMessage(text: "hello", user: user, createdAt: DateTime.now()), - ]); - } - - void systemMessage() { - Timer(Duration(milliseconds: 300), () { - if (i < 6) { - if (mounted) if (m.length > i) - setState(() { - messages = [...messages, m[i]]; - // messages = [] - // ..addAll(messages) - // ..add(m[i]); - }); - i++; - } - Timer(Duration(milliseconds: 300), () { - _chatViewKey.currentState.scrollController - ..animateTo( - _chatViewKey.currentState.scrollController.position.maxScrollExtent, - curve: Curves.easeOut, - duration: const Duration(milliseconds: 300), - ); - }); - }); - } - - void onSend(ChatMessage message) { - print(message.toJson()); - _chatConfig.sendMessage(message); - // var documentReference = Firestore.instance - // .collection('messages') - // .document(DateTime.now().millisecondsSinceEpoch.toString()); - - // Firestore.instance.runTransaction((transaction) async { - // await transaction.set( - // documentReference, - // message.toJson(), - // ); - // }); - setState(() { - //messages = [...messages, message]; - messages = [] - ..addAll(messages) - ..add(message); - print(messages.length); - }); - - if (i == 0) { - systemMessage(); - Timer(Duration(milliseconds: 600), () { - systemMessage(); - }); - } else { - systemMessage(); - } } @override @@ -145,144 +35,5 @@ class _ChatFragmentState extends State { initialChild: Center(child: Container(child: CircularProgressIndicator())), ); - return Scaffold( - extendBody: false, - appBar: CupertinoNavigationBar( - automaticallyImplyMiddle: true, - automaticallyImplyLeading: true, - leading: IconButton( - icon: Icon(CupertinoIcons.back), - onPressed: () { - ///Dispose of the message streams and sinks as they are no longer needed - _chatConfig.dispose(); - if (Navigator.of(context).canPop()) Navigator.of(context).pop(); - }), - ), - body: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Flexible( - flex: 1, - child: DashChat( - height: MediaQuery.of(context).size.height - 120.0, - key: _chatViewKey, - inverted: false, - onSend: onSend, - user: user, - - inputDecoration: InputDecoration(hintText: "Add message here..."), - dateFormat: DateFormat('yyyy-MMM-dd'), - timeFormat: DateFormat('HH:mm'), - messages: messages, - showUserAvatar: true, - showAvatarForEveryMessage: false, - scrollToBottom: true, - // inputFooterBuilder: () { - // return Column( - // children: [ - // Text('asd'), - // Text('asd'), - // Text('asd'), - // Text('asd'), - // Text('asd'), - // Text('asd'), - // ], - // ); - // }, - onPressAvatar: (ChatUser user) { - print("OnPressAvatar: ${user.name}"); - }, - onLongPressAvatar: (ChatUser user) { - print("OnLongPressAvatar: ${user.name}"); - }, - inputMaxLines: 5, - alwaysShowSend: true, - inputTextStyle: TextStyle(fontSize: 16.0), - inputContainerStyle: BoxDecoration( - border: Border.all(width: 0.0), - color: Colors.white, - ), - onQuickReply: (Reply reply) { - setState(() { - messages.add(ChatMessage( - text: reply.value, - createdAt: DateTime.now(), - user: user)); - - messages = []..addAll(messages); - }); - - Timer(Duration(milliseconds: 300), () { - _chatViewKey.currentState.scrollController - ..animateTo( - _chatViewKey.currentState.scrollController.position - .maxScrollExtent, - curve: Curves.easeOut, - duration: const Duration(milliseconds: 300), - ); - - if (i == 0) { - systemMessage(); - Timer(Duration(milliseconds: 600), () { - systemMessage(); - }); - } else { - systemMessage(); - } - }); - }, - onLoadEarlier: () { - print("laoding..."); - }, - shouldShowLoadEarlier: false, - showTraillingBeforeSend: true, - trailing: [ - IconButton( - icon: Icon(Icons.photo), - onPressed: () async { - File result = await ImagePicker.pickImage( - source: ImageSource.gallery, - maxHeight: 400, - maxWidth: 400, - ); - - // if (result != null) { - // final StorageReference storageRef = - // FirebaseStorage.instance.ref().child("chat_images"); - - // StorageUploadTask uploadTask = storageRef.putFile( - // result, - // StorageMetadata( - // contentType: 'image/jpg', - // ), - // ); - // StorageTaskSnapshot download = - // await uploadTask.onComplete; - - // String url = await download.ref.getDownloadURL(); - - // ChatMessage message = - // ChatMessage(text: "", user: user, image: url); - - // var documentReference = Firestore.instance - // .collection('messages') - // .document( - // DateTime.now().millisecondsSinceEpoch.toString()); - - // Firestore.instance.runTransaction((transaction) async { - // await transaction.set( - // documentReference, - // message.toJson(), - // ); - // }); - // } - }, - ) - ], - ), - ), - ], - ), - ); } }