Skip to content

Commit

Permalink
Merge pull request #8 from SimCoderYoutube/lesson_8/search__for_users…
Browse files Browse the repository at this point in the history
…_using_a_firestore_query

[Add] search for users and profile abstraction
  • Loading branch information
SimCoderYoutube committed Mar 8, 2021
2 parents aab500d + c448de2 commit 60bfec9
Show file tree
Hide file tree
Showing 6 changed files with 176 additions and 19 deletions.
15 changes: 15 additions & 0 deletions frontend/lib/screens/home/feed.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import 'package:flutter/material.dart';

class Feed extends StatefulWidget {
Feed({Key key}) : super(key: key);

@override
FeedState createState() => FeedState();
}

class FeedState extends State<Feed> {
@override
Widget build(BuildContext context) {
return Text('feed');
}
}
38 changes: 38 additions & 0 deletions frontend/lib/screens/home/search.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:twitter/screens/main/profile/list.dart';
import 'package:twitter/services/user.dart';

class Search extends StatefulWidget {
Search({Key key}) : super(key: key);

@override
_SearchState createState() => _SearchState();
}

class _SearchState extends State<Search> {
UserService _userService = UserService();
String search = '';
@override
Widget build(BuildContext context) {
return StreamProvider.value(
value: _userService.queryByName(search),
child: Column(
children: [
Padding(
padding: EdgeInsets.all(10),
child: TextField(
onChanged: (text) {
setState(() {
search = text;
});
},
decoration: InputDecoration(hintText: 'Search...'),
),
),
ListUsers()
],
),
);
}
}
37 changes: 33 additions & 4 deletions frontend/lib/screens/main/home.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,29 @@
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:twitter/screens/home/feed.dart';
import 'package:twitter/screens/home/search.dart';
import 'package:twitter/services/auth.dart';

class Home extends StatelessWidget {
const Home({Key key}) : super(key: key);
class Home extends StatefulWidget {
Home({Key key}) : super(key: key);

@override
_HomeState createState() => _HomeState();
}

class _HomeState extends State<Home> {
final AuthService _authService = AuthService();
int _currentIndex = 0;
final List<Widget> _children = [Feed(), Search()];

void onTabPressed(int index) {
setState(() {
_currentIndex = index;
});
}

@override
Widget build(BuildContext context) {
final AuthService _authService = AuthService();
return Scaffold(
appBar: AppBar(
title: Text("Home"),
Expand All @@ -26,7 +43,8 @@ class Home extends StatelessWidget {
ListTile(
title: Text('Profile'),
onTap: () {
Navigator.pushNamed(context, '/profile');
Navigator.pushNamed(context, '/profile',
arguments: FirebaseAuth.instance.currentUser.uid);
},
),
ListTile(
Expand All @@ -38,6 +56,17 @@ class Home extends StatelessWidget {
],
),
),
bottomNavigationBar: BottomNavigationBar(
onTap: onTabPressed,
currentIndex: _currentIndex,
showSelectedLabels: false,
showUnselectedLabels: false,
items: [
BottomNavigationBarItem(icon: new Icon(Icons.home), label: 'home'),
BottomNavigationBarItem(icon: new Icon(Icons.search), label: 'search')
],
),
body: _children[_currentIndex],
);
}
}
50 changes: 50 additions & 0 deletions frontend/lib/screens/main/profile/list.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import 'dart:developer';

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:twitter/models/user.dart';

class ListUsers extends StatefulWidget {
ListUsers({Key key}) : super(key: key);

@override
_ListUsersState createState() => _ListUsersState();
}

class _ListUsersState extends State<ListUsers> {
@override
Widget build(BuildContext context) {
final users = Provider.of<List<UserModel>>(context) ?? [];

return ListView.builder(
shrinkWrap: true,
itemCount: users.length,
itemBuilder: (context, index) {
final user = users[index];
return InkWell(
onTap: () =>
Navigator.pushNamed(context, '/profile', arguments: user.id),
child: Column(
children: [
Padding(
padding: EdgeInsets.all(10),
child: Row(children: [
user.profileImageUrl != ''
? CircleAvatar(
radius: 20,
backgroundImage:
NetworkImage(user.profileImageUrl),
)
: Icon(Icons.person, size: 40),
SizedBox(width: 10),
Text(user.name)
])),
const Divider(
thickness: 1,
)
],
),
);
});
}
}
24 changes: 13 additions & 11 deletions frontend/lib/screens/main/profile/profile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,14 @@ class _ProfileState extends State<Profile> {

@override
Widget build(BuildContext context) {
final String uid = ModalRoute.of(context).settings.arguments;
return MultiProvider(
providers: [
StreamProvider.value(
value: _postService
.getPostsByUser(FirebaseAuth.instance.currentUser.uid),
value: _postService.getPostsByUser(uid),
),
StreamProvider.value(
value:
_userService.getUserInfo(FirebaseAuth.instance.currentUser.uid),
value: _userService.getUserInfo(uid),
)
],
child: Scaffold(
Expand Down Expand Up @@ -56,13 +55,16 @@ class _ProfileState extends State<Profile> {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Image.network(
Provider.of<UserModel>(context)
.profileImageUrl ??
'',
height: 60,
fit: BoxFit.cover,
),
Provider.of<UserModel>(context)
.profileImageUrl !=
''
? CircleAvatar(
radius: 30,
backgroundImage: NetworkImage(
Provider.of<UserModel>(context)
.profileImageUrl),
)
: Icon(Icons.person, size: 50),
FlatButton(
onPressed: () {
Navigator.pushNamed(context, '/edit');
Expand Down
31 changes: 27 additions & 4 deletions frontend/lib/services/user.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,26 @@ import 'package:twitter/services/utils.dart';
class UserService {
UtilsService _utilsService = UtilsService();

List<UserModel> _userListFromQuerySnapshot(QuerySnapshot snapshot) {
return snapshot.docs.map((doc) {
return UserModel(
id: doc.id,
name: doc.data()['name'] ?? '',
profileImageUrl: doc.data()['profileImageUrl'] ?? '',
bannerImageUrl: doc.data()['bannerImageUrl'] ?? '',
email: doc.data()['email'] ?? '',
);
}).toList();
}

UserModel _userFromFirebaseSnapshot(DocumentSnapshot snapshot) {
return snapshot != null
? UserModel(
id: snapshot.id,
name: snapshot.data()['name'],
profileImageUrl: snapshot.data()['profileImageUrl'],
bannerImageUrl: snapshot.data()['bannerImageUrl'],
email: snapshot.data()['email'],
name: snapshot.data()['name'] ?? '',
profileImageUrl: snapshot.data()['profileImageUrl'] ?? '',
bannerImageUrl: snapshot.data()['bannerImageUrl'] ?? '',
email: snapshot.data()['email'] ?? '',
)
: null;
}
Expand All @@ -30,6 +42,17 @@ class UserService {
.map(_userFromFirebaseSnapshot);
}

Stream<List<UserModel>> queryByName(search) {
return FirebaseFirestore.instance
.collection("users")
.orderBy("name")
.startAt([search])
.endAt([search + '\uf8ff'])
.limit(10)
.snapshots()
.map(_userListFromQuerySnapshot);
}

Future<void> updateProfile(
File _bannerImage, File _profileImage, String name) async {
String bannerImageUrl = '';
Expand Down

0 comments on commit 60bfec9

Please sign in to comment.