| @ -0,0 +1,9 @@ | |||
| package Models | |||
| import "github.com/gofrs/uuid" | |||
| type Friend struct { | |||
| Base | |||
| UserID uuid.UUID `gorm:"type:uuid;column:user_id;not null;" json:"user_id"` | |||
| FriendId string `gorm:"column:friend_id;not null" json:"friend_id"` // Stored encrypted | |||
| } | |||
| @ -1,25 +1,52 @@ | |||
| import 'package:flutter/material.dart'; | |||
| import '/views/main/conversations_list.dart'; | |||
| import '/views/main/home.dart'; | |||
| import '/views/authentication/unauthenticated_landing.dart'; | |||
| import '/views/authentication/login.dart'; | |||
| import '/views/authentication/signup.dart'; | |||
| void main() { | |||
| runApp(const Home()); | |||
| runApp(const MyApp()); | |||
| } | |||
| class Home extends StatelessWidget { | |||
| const Home({Key? key}) : super(key: key); | |||
| class MyApp extends StatelessWidget { | |||
| const MyApp({Key? key}) : super(key: key); | |||
| static const String _title = 'Envelope'; | |||
| @override | |||
| Widget build(BuildContext context) { | |||
| return const MaterialApp( | |||
| return MaterialApp( | |||
| title: _title, | |||
| home: Scaffold( | |||
| routes: { | |||
| '/home': (context) => const Home(), | |||
| '/landing': (context) => const UnauthenticatedLandingWidget(), | |||
| '/login': (context) => const Login(), | |||
| '/signup': (context) => const Signup(), | |||
| }, | |||
| home: const Scaffold( | |||
| backgroundColor: Colors.cyan, | |||
| body: SafeArea( | |||
| child: ConversationsList(), | |||
| child: Home(), | |||
| ) | |||
| ) | |||
| ), | |||
| theme: ThemeData( | |||
| appBarTheme: const AppBarTheme( | |||
| backgroundColor: Colors.cyan, | |||
| elevation: 0, | |||
| ), | |||
| inputDecorationTheme: const InputDecorationTheme( | |||
| border: OutlineInputBorder(), | |||
| focusedBorder: OutlineInputBorder(), | |||
| labelStyle: TextStyle( | |||
| color: Colors.white, | |||
| fontSize: 30, | |||
| ), | |||
| filled: true, | |||
| fillColor: Colors.white, | |||
| ), | |||
| ), | |||
| ); | |||
| } | |||
| } | |||
| @ -0,0 +1,9 @@ | |||
| class Friend{ | |||
| String id; | |||
| String username; | |||
| Friend({ | |||
| required this.id, | |||
| required this.username, | |||
| }); | |||
| } | |||
| @ -0,0 +1,56 @@ | |||
| import 'package:flutter/material.dart'; | |||
| import 'package:shared_preferences/shared_preferences.dart'; | |||
| class ConversationList extends StatefulWidget { | |||
| const ConversationList({Key? key}) : super(key: key); | |||
| @override | |||
| State<ConversationList> createState() => _ConversationListState(); | |||
| } | |||
| class _ConversationListState extends State<ConversationList> { | |||
| final _suggestions = <String>[]; | |||
| final _biggerFont = const TextStyle(fontSize: 18); | |||
| Widget list() { | |||
| if (_suggestions.isEmpty) { | |||
| return const Center( | |||
| child: Text('No Conversations'), | |||
| ); | |||
| } | |||
| return ListView.builder( | |||
| itemCount: _suggestions.length, | |||
| padding: const EdgeInsets.all(16.0), | |||
| itemBuilder: /*1*/ (context, i) { | |||
| //if (i >= _suggestions.length) { | |||
| // TODO: Check for more conversations here. Remove the itemCount to use this section | |||
| //_suggestions.addAll(generateWordPairs().take(10)); /*4*/ | |||
| //} | |||
| return Column( | |||
| children: [ | |||
| ListTile( | |||
| title: Text( | |||
| _suggestions[i], | |||
| style: _biggerFont, | |||
| ), | |||
| ), | |||
| const Divider(), | |||
| ] | |||
| ); | |||
| }, | |||
| ); | |||
| } | |||
| @override | |||
| Widget build(BuildContext context) { | |||
| return Scaffold( | |||
| appBar: AppBar( | |||
| title: const Text('Envelope'), | |||
| ), | |||
| body: list(), | |||
| ); | |||
| } | |||
| } | |||
| @ -1,112 +0,0 @@ | |||
| import 'package:flutter/material.dart'; | |||
| import 'package:shared_preferences/shared_preferences.dart'; | |||
| import 'package:font_awesome_flutter/font_awesome_flutter.dart'; | |||
| import '/views/authentication/unauthenticated_landing.dart'; | |||
| class ConversationsList extends StatefulWidget { | |||
| const ConversationsList({Key? key}) : super(key: key); | |||
| @override | |||
| State<ConversationsList> createState() => _ConversationsListState(); | |||
| } | |||
| class _ConversationsListState extends State<ConversationsList> { | |||
| @override | |||
| void initState() { | |||
| checkLogin(); | |||
| super.initState(); | |||
| } | |||
| final _suggestions = <String>[]; | |||
| final _biggerFont = const TextStyle(fontSize: 18); | |||
| Future checkLogin() async { | |||
| SharedPreferences preferences = await SharedPreferences.getInstance(); | |||
| print(preferences.getBool('islogin')); | |||
| if (preferences.getBool('islogin') != true) { | |||
| setState(() { | |||
| Navigator.of(context).push(MaterialPageRoute( | |||
| builder: (context) => const UnauthenticatedLandingWidget(), | |||
| )); | |||
| }); | |||
| } | |||
| } | |||
| Widget list() { | |||
| if (_suggestions.isEmpty) { | |||
| return const Center( | |||
| child: Text('No Conversations'), | |||
| ); | |||
| } | |||
| return ListView.builder( | |||
| itemCount: _suggestions.length, | |||
| padding: const EdgeInsets.all(16.0), | |||
| itemBuilder: /*1*/ (context, i) { | |||
| //if (i >= _suggestions.length) { | |||
| // TODO: Check for more conversations here. Remove the itemCount to use this section | |||
| //_suggestions.addAll(generateWordPairs().take(10)); /*4*/ | |||
| //} | |||
| return Column( | |||
| children: [ | |||
| ListTile( | |||
| title: Text( | |||
| _suggestions[i], | |||
| style: _biggerFont, | |||
| ), | |||
| ), | |||
| const Divider(), | |||
| ] | |||
| ); | |||
| }, | |||
| ); | |||
| } | |||
| @override | |||
| Widget build(BuildContext context) { | |||
| return WillPopScope( | |||
| onWillPop: () async => false, | |||
| child: Scaffold( | |||
| appBar: AppBar( | |||
| title: Text('Envelope'), | |||
| actions: <Widget>[ | |||
| PopupMenuButton( | |||
| icon: const FaIcon(FontAwesomeIcons.ellipsisVertical, color: Colors.white, size: 40), | |||
| itemBuilder: (context) => [ | |||
| const PopupMenuItem<int>( | |||
| value: 0, | |||
| child: Text("Settings"), | |||
| ), | |||
| const PopupMenuItem<int>( | |||
| value: 1, | |||
| child: Text("Logout"), | |||
| ), | |||
| ], | |||
| onSelected: (item) => selectedMenuItem(context, item), | |||
| ), | |||
| ], | |||
| ), | |||
| body: list(), | |||
| ), | |||
| ); | |||
| } | |||
| void selectedMenuItem(BuildContext context, item) async { | |||
| switch (item) { | |||
| case 0: | |||
| print("Settings"); | |||
| break; | |||
| case 1: | |||
| SharedPreferences preferences = await SharedPreferences.getInstance(); | |||
| preferences.setBool('islogin', false); | |||
| Navigator.of(context).push(MaterialPageRoute( | |||
| builder: (context) => const UnauthenticatedLandingWidget(), | |||
| )); | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| @ -0,0 +1,105 @@ | |||
| import 'package:flutter/material.dart'; | |||
| import '/models/friends.dart'; | |||
| import '/views/main/friend_list_item.dart'; | |||
| class FriendList extends StatefulWidget { | |||
| const FriendList({Key? key}) : super(key: key); | |||
| @override | |||
| State<FriendList> createState() => _FriendListState(); | |||
| } | |||
| class _FriendListState extends State<FriendList> { | |||
| List<Friend> friends = [ | |||
| Friend(id: 'abc', username: 'Test1'), | |||
| Friend(id: 'abc', username: 'Test2'), | |||
| Friend(id: 'abc', username: 'Test3'), | |||
| Friend(id: 'abc', username: 'Test4'), | |||
| Friend(id: 'abc', username: 'Test5'), | |||
| ]; | |||
| Widget list() { | |||
| if (friends.isEmpty) { | |||
| return const Center( | |||
| child: Text('No Friends'), | |||
| ); | |||
| } | |||
| return ListView.builder( | |||
| itemCount: friends.length, | |||
| shrinkWrap: true, | |||
| padding: const EdgeInsets.only(top: 16), | |||
| physics: const NeverScrollableScrollPhysics(), | |||
| itemBuilder: (context, i) { | |||
| return FriendListItem( | |||
| id: friends[i].id, | |||
| username: friends[i].username, | |||
| ); | |||
| }, | |||
| ); | |||
| } | |||
| @override | |||
| Widget build(BuildContext context) { | |||
| return Scaffold( | |||
| body: SingleChildScrollView( | |||
| physics: const BouncingScrollPhysics(), | |||
| child: Column( | |||
| crossAxisAlignment: CrossAxisAlignment.start, | |||
| children: <Widget>[ | |||
| SafeArea( | |||
| child: Padding( | |||
| padding: const EdgeInsets.only(left: 16,right: 16,top: 10), | |||
| child: Row( | |||
| mainAxisAlignment: MainAxisAlignment.spaceBetween, | |||
| children: <Widget>[ | |||
| const Text("Friends",style: TextStyle(fontSize: 32,fontWeight: FontWeight.bold),), | |||
| Container( | |||
| padding: const EdgeInsets.only(left: 8,right: 8,top: 2,bottom: 2), | |||
| height: 30, | |||
| decoration: BoxDecoration( | |||
| borderRadius: BorderRadius.circular(30), | |||
| color: Colors.pink[50], | |||
| ), | |||
| child: Row( | |||
| children: const <Widget>[ | |||
| Icon(Icons.add,color: Colors.pink,size: 20,), | |||
| SizedBox(width: 2,), | |||
| Text("Add",style: TextStyle(fontSize: 14,fontWeight: FontWeight.bold),), | |||
| ], | |||
| ), | |||
| ) | |||
| ], | |||
| ), | |||
| ), | |||
| ), | |||
| Padding( | |||
| padding: const EdgeInsets.only(top: 16,left: 16,right: 16), | |||
| child: TextField( | |||
| decoration: InputDecoration( | |||
| hintText: "Search...", | |||
| hintStyle: TextStyle(color: Colors.grey.shade600), | |||
| prefixIcon: Icon(Icons.search,color: Colors.grey.shade600, size: 20,), | |||
| filled: true, | |||
| fillColor: Colors.grey.shade100, | |||
| contentPadding: const EdgeInsets.all(8), | |||
| enabledBorder: OutlineInputBorder( | |||
| borderRadius: BorderRadius.circular(20), | |||
| borderSide: BorderSide( | |||
| color: Colors.grey.shade100 | |||
| ) | |||
| ), | |||
| ), | |||
| ), | |||
| ), | |||
| Padding( | |||
| padding: const EdgeInsets.only(top: 16,left: 16,right: 16), | |||
| child: list(), | |||
| ), | |||
| ], | |||
| ), | |||
| ), | |||
| ); | |||
| } | |||
| } | |||
| @ -0,0 +1,56 @@ | |||
| import 'package:flutter/material.dart'; | |||
| class FriendListItem extends StatefulWidget{ | |||
| final String id; | |||
| final String username; | |||
| const FriendListItem({ | |||
| Key? key, | |||
| required this.id, | |||
| required this.username, | |||
| }) : super(key: key); | |||
| @override | |||
| _FriendListItemState createState() => _FriendListItemState(); | |||
| } | |||
| class _FriendListItemState extends State<FriendListItem> { | |||
| @override | |||
| Widget build(BuildContext context) { | |||
| return GestureDetector( | |||
| onTap: (){ | |||
| }, | |||
| child: Container( | |||
| padding: const EdgeInsets.only(left: 16,right: 16,top: 10,bottom: 10), | |||
| child: Row( | |||
| children: <Widget>[ | |||
| Expanded( | |||
| child: Row( | |||
| children: <Widget>[ | |||
| // CircleAvatar( | |||
| // backgroundImage: NetworkImage(widget.imageUrl), | |||
| // maxRadius: 30, | |||
| // ), | |||
| //const SizedBox(width: 16), | |||
| Expanded( | |||
| child: Container( | |||
| color: Colors.transparent, | |||
| child: Column( | |||
| crossAxisAlignment: CrossAxisAlignment.start, | |||
| children: <Widget>[ | |||
| Text(widget.username, style: const TextStyle(fontSize: 16)), | |||
| const SizedBox(height: 6), | |||
| //Text(widget.messageText,style: TextStyle(fontSize: 13,color: Colors.grey.shade600, fontWeight: widget.isMessageRead?FontWeight.bold:FontWeight.normal),), | |||
| const Divider(), | |||
| ], | |||
| ), | |||
| ), | |||
| ), | |||
| ], | |||
| ), | |||
| ), | |||
| ], | |||
| ), | |||
| ), | |||
| ); | |||
| } | |||
| } | |||
| @ -0,0 +1,72 @@ | |||
| import 'package:flutter/material.dart'; | |||
| import 'package:shared_preferences/shared_preferences.dart'; | |||
| import '/views/main/conversation_list.dart'; | |||
| import '/views/main/friend_list.dart'; | |||
| class Home extends StatefulWidget { | |||
| const Home({Key? key}) : super(key: key); | |||
| @override | |||
| State<Home> createState() => _HomeState(); | |||
| } | |||
| class _HomeState extends State<Home> { | |||
| @override | |||
| void initState() { | |||
| checkLogin(); | |||
| super.initState(); | |||
| } | |||
| Future checkLogin() async { | |||
| SharedPreferences preferences = await SharedPreferences.getInstance(); | |||
| if (preferences.getBool('islogin') != true) { | |||
| Navigator.pushNamedAndRemoveUntil(context, '/landing', ModalRoute.withName('/landing')); | |||
| } | |||
| } | |||
| int _selectedIndex = 0; | |||
| static const List<Widget> _widgetOptions = <Widget>[ | |||
| ConversationList(), | |||
| FriendList(), | |||
| Text('Not Implemented'), | |||
| ]; | |||
| void _onItemTapped(int index) { | |||
| setState(() { | |||
| _selectedIndex = index; | |||
| }); | |||
| } | |||
| @override | |||
| Widget build(BuildContext context) { | |||
| return WillPopScope( | |||
| onWillPop: () async => false, | |||
| child: Scaffold( | |||
| body: _widgetOptions.elementAt(_selectedIndex), | |||
| bottomNavigationBar: BottomNavigationBar( | |||
| currentIndex: _selectedIndex, | |||
| onTap: _onItemTapped, | |||
| selectedItemColor: Colors.red, | |||
| unselectedItemColor: Colors.grey.shade600, | |||
| selectedLabelStyle: const TextStyle(fontWeight: FontWeight.w600), | |||
| unselectedLabelStyle: const TextStyle(fontWeight: FontWeight.w600), | |||
| type: BottomNavigationBarType.fixed, | |||
| items: const [ | |||
| BottomNavigationBarItem( | |||
| icon: Icon(Icons.message), | |||
| label: "Chats", | |||
| ), | |||
| BottomNavigationBarItem( | |||
| icon: Icon(Icons.group_work), | |||
| label: "Friends", | |||
| ), | |||
| BottomNavigationBarItem( | |||
| icon: Icon(Icons.account_box), | |||
| label: "Profile", | |||
| ), | |||
| ], | |||
| ), | |||
| ), | |||
| ); | |||
| } | |||
| } | |||