@ -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 '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() { | 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'; | static const String _title = 'Envelope'; | ||||
@override | @override | ||||
Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
return const MaterialApp( | |||||
return MaterialApp( | |||||
title: _title, | 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, | backgroundColor: Colors.cyan, | ||||
body: SafeArea( | 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", | |||||
), | |||||
], | |||||
), | |||||
), | |||||
); | |||||
} | |||||
} |