Skip to content

Commit 7195d3f

Browse files
authored
feat: home (fireship-io#3)
* feat: add about view * feat: add profile view * chore(shared): export provider * feat: add bottom nav bar * feat: add home page
1 parent 3ee8da0 commit 7195d3f

File tree

16 files changed

+224
-28
lines changed

16 files changed

+224
-28
lines changed

lib/about/about.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export 'view/view.dart';

lib/about/view/about_view.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import 'package:flutter/material.dart';
2+
3+
class AboutView extends StatelessWidget {
4+
const AboutView({Key? key}) : super(key: key);
5+
6+
@override
7+
Widget build(BuildContext context) {
8+
return const Center(
9+
child: Text('About this app...'),
10+
);
11+
}
12+
}

lib/about/view/view.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export 'about_view.dart';

lib/app/app_pages.dart

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import 'package:flutter/material.dart';
22
import 'package:flutter/widgets.dart';
3-
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
3+
import 'package:quizapp/home/home.dart';
44
import 'package:quizapp/login/login.dart';
5-
import 'package:flutter_bloc/flutter_bloc.dart';
65

76
import 'cubit/app_cubit.dart';
87

@@ -15,33 +14,8 @@ class AppPages {
1514
return [LoginPage.page()];
1615
}
1716
if (status.isNewlyAuthenticated) {
18-
return [
19-
const MaterialPage(
20-
child: TopicsPage(),
21-
)
22-
];
17+
return [HomePage.page()];
2318
}
2419
return pages;
2520
}
2621
}
27-
28-
class TopicsPage extends StatelessWidget {
29-
const TopicsPage({Key? key}) : super(key: key);
30-
31-
@override
32-
Widget build(BuildContext context) {
33-
return Scaffold(
34-
appBar: AppBar(
35-
title: const Text('Topics'),
36-
actions: [
37-
IconButton(
38-
onPressed: () {
39-
context.read<AppCubit>().logOut();
40-
},
41-
icon: const Icon(FontAwesomeIcons.signOutAlt),
42-
),
43-
],
44-
),
45-
);
46-
}
47-
}

lib/home/home.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export 'view/view.dart';

lib/home/view/bottom_nav_bar.dart

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
3+
import 'package:quizapp/l10n/l10n.dart';
4+
import 'package:quizapp/shared/shared.dart';
5+
import 'package:shared/shared.dart';
6+
7+
enum NavBarItem { topics, about, profile }
8+
9+
extension NavBarItemExtensions on NavBarItem {
10+
bool get isTopics => this == NavBarItem.topics;
11+
}
12+
13+
class NavBarController extends PageController {
14+
NavBarController({NavBarItem initialItem = NavBarItem.topics})
15+
: _notifier = ValueNotifier<NavBarItem>(initialItem),
16+
super(initialPage: initialItem.index) {
17+
_notifier.addListener(_listener);
18+
}
19+
20+
final ValueNotifier<NavBarItem> _notifier;
21+
22+
NavBarItem get item => _notifier.value;
23+
set item(NavBarItem newItem) => _notifier.value = newItem;
24+
25+
void _listener() {
26+
jumpToPage(item.index);
27+
}
28+
29+
@override
30+
void dispose() {
31+
_notifier.dispose();
32+
super.dispose();
33+
}
34+
}
35+
36+
class BottomNavBar extends StatelessWidget {
37+
const BottomNavBar({Key? key}) : super(key: key);
38+
39+
@override
40+
Widget build(BuildContext context) {
41+
final l10n = context.l10n;
42+
return Theme(
43+
data: context.theme.copyWith(
44+
highlightColor: Colors.transparent,
45+
splashColor: Colors.transparent,
46+
),
47+
child: BottomNavigationBar(
48+
onTap: (index) {
49+
context.read<NavBarController>().item = NavBarItem.values[index];
50+
},
51+
currentIndex: context
52+
.select((NavBarController controller) => controller.item.index),
53+
items: [
54+
BottomNavigationBarItem(
55+
label: l10n.topicsLabel,
56+
icon: const Icon(FontAwesomeIcons.graduationCap),
57+
),
58+
BottomNavigationBarItem(
59+
label: l10n.aboutLabel,
60+
icon: const Icon(FontAwesomeIcons.bolt),
61+
),
62+
BottomNavigationBarItem(
63+
label: l10n.profileLabel,
64+
icon: const Icon(FontAwesomeIcons.userCircle),
65+
),
66+
],
67+
),
68+
);
69+
}
70+
}

lib/home/view/home_page.dart

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
3+
import 'package:quizapp/about/about.dart';
4+
import 'package:quizapp/l10n/l10n.dart';
5+
import 'package:quizapp/profile/profile.dart';
6+
import 'package:provider/provider.dart';
7+
import 'package:quizapp/shared/shared.dart';
8+
9+
import 'bottom_nav_bar.dart';
10+
11+
class HomePage extends StatelessWidget {
12+
const HomePage._({Key? key}) : super(key: key);
13+
14+
static Page page() => const MaterialPage<void>(child: HomePage._());
15+
16+
@override
17+
Widget build(BuildContext context) {
18+
return ListenableProvider(
19+
create: (_) => NavBarController(),
20+
child: Scaffold(
21+
appBar: AppBar(
22+
title: const _HomeTitle(),
23+
actions: const [_ProfileButton()],
24+
),
25+
body: const _HomeBody(),
26+
bottomNavigationBar: const BottomNavBar(),
27+
),
28+
);
29+
}
30+
}
31+
32+
class _HomeTitle extends StatelessWidget {
33+
const _HomeTitle({Key? key}) : super(key: key);
34+
35+
@override
36+
Widget build(BuildContext context) {
37+
final navBarItem =
38+
context.select((NavBarController controller) => controller.item);
39+
return Text(context.l10n.navBarItem(navBarItem));
40+
}
41+
}
42+
43+
class _ProfileButton extends StatelessWidget {
44+
const _ProfileButton({Key? key}) : super(key: key);
45+
46+
@override
47+
Widget build(BuildContext context) {
48+
final navBarItem =
49+
context.select((NavBarController controller) => controller.item);
50+
return navBarItem.isTopics
51+
? IconButton(
52+
icon: const Icon(
53+
FontAwesomeIcons.userCircle,
54+
color: kPink,
55+
),
56+
onPressed: () =>
57+
context.read<NavBarController>().item = NavBarItem.profile,
58+
)
59+
: const Empty();
60+
}
61+
}
62+
63+
class _HomeBody extends StatelessWidget {
64+
const _HomeBody({Key? key}) : super(key: key);
65+
66+
@override
67+
Widget build(BuildContext context) {
68+
return PageView(
69+
controller: context.read<NavBarController>(),
70+
physics: const NeverScrollableScrollPhysics(),
71+
children: const [
72+
AboutView(),
73+
AboutView(),
74+
ProfileView(),
75+
],
76+
);
77+
}
78+
}
79+
80+
extension _AppLocalizationsExtensions on AppLocalizations {
81+
String navBarItem(NavBarItem item) {
82+
switch (item) {
83+
case NavBarItem.topics:
84+
return topicsLabel;
85+
case NavBarItem.about:
86+
return aboutLabel;
87+
case NavBarItem.profile:
88+
return profileLabel;
89+
default:
90+
throw UnimplementedError('$item');
91+
}
92+
}
93+
}

lib/home/view/view.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export 'home_page.dart';

lib/l10n/arb/app_en.arb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,5 +51,17 @@
5151
"loginAsGuestButtonLabel": "Continue as Guest",
5252
"@loginAsGuestButtonLabel": {
5353
"description": "Sign in as guest button label"
54+
},
55+
"topicsLabel": "Topics",
56+
"@topicsLabel": {
57+
"description": "Topics label"
58+
},
59+
"aboutLabel": "About",
60+
"@aboutLabel": {
61+
"description": "About label"
62+
},
63+
"profileLabel": "Profile",
64+
"@profileLabel": {
65+
"description": "Profile label"
5466
}
5567
}

lib/profile/profile.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export 'view/view.dart';

0 commit comments

Comments
 (0)