Skip to content

Commit f8f4af4

Browse files
committed
feat: implement basic skeleton of home view
1 parent 86a332a commit f8f4af4

11 files changed

Lines changed: 261 additions & 0 deletions

File tree

lib/data/constants/assets.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,10 @@ class AppAssets {
2222
static const String feedCardIllustration =
2323
'$_illustrationsRoot/feed_card.png';
2424
static const String profileIllustration = '$_illustrationsRoot/profile.png';
25+
26+
/// BottomNavigationBar Icons
27+
static const String feed = '$_iconsRoot/feed.svg';
28+
static const String contest = '$_iconsRoot/contest.svg';
29+
static const String search = '$_iconsRoot/search.svg';
30+
static const String profile = '$_iconsRoot/profile.svg';
2531
}
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 ContestsScreen extends StatelessWidget {
4+
const ContestsScreen({Key? key}) : super(key: key);
5+
6+
@override
7+
Widget build(BuildContext context) {
8+
return const Center(
9+
child: Text('Contest Screen'),
10+
);
11+
}
12+
}

lib/presentation/core/router.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import 'package:flutter/material.dart';
2+
import 'package:flutter_bloc/flutter_bloc.dart';
23
import 'package:get/get.dart';
34

45
import '../../data/constants/routes.dart';
6+
import '../home/bloc/home_bloc.dart';
7+
import '../home/home_screen.dart';
58
import '../login/login_screen.dart';
69
import '../onboarding/onboarding_screen.dart';
710

@@ -21,6 +24,15 @@ class AppRouter {
2124
routeName: settings.name,
2225
settings: settings,
2326
);
27+
case AppRoutes.home:
28+
return GetPageRoute(
29+
page: () => BlocProvider(
30+
create: (context) => HomeBloc()..init(),
31+
child: const HomeScreen(),
32+
),
33+
routeName: settings.name,
34+
settings: settings,
35+
);
2436
default:
2537
return GetPageRoute(
2638
page: () => Scaffold(
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 FeedScreen extends StatelessWidget {
4+
const FeedScreen({Key? key}) : super(key: key);
5+
6+
@override
7+
Widget build(BuildContext context) {
8+
return const Center(
9+
child: Text('Feed Screen'),
10+
);
11+
}
12+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import 'package:equatable/equatable.dart';
2+
import 'package:flutter/widgets.dart';
3+
import 'package:flutter_bloc/flutter_bloc.dart';
4+
import 'package:freezed_annotation/freezed_annotation.dart';
5+
6+
import '../../contests/contests_screen.dart';
7+
import '../../feed/feed_screen.dart';
8+
import '../../profile/profile_screen.dart';
9+
import '../../search/search_screen.dart';
10+
11+
part 'home_event.dart';
12+
part 'home_state.dart';
13+
part 'home_bloc.freezed.dart';
14+
15+
class HomeBloc extends Bloc<HomeEvent, HomeState> {
16+
HomeBloc() : super(const HomeState()) {
17+
on<BottomNavItemPressed>(_changeScreen);
18+
}
19+
late final List<Widget> screens;
20+
21+
void init() {
22+
screens = const <Widget>[
23+
FeedScreen(),
24+
ContestsScreen(),
25+
SearchScreen(),
26+
ProfileScreen(),
27+
];
28+
}
29+
30+
void _changeScreen(BottomNavItemPressed event, Emitter<HomeState> emit) {
31+
if (state.selectedIndex == event.index) return;
32+
33+
emit(state.copyWith(
34+
screen: screens[event.index],
35+
selectedIndex: event.index,
36+
));
37+
}
38+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
part of 'home_bloc.dart';
2+
3+
abstract class HomeEvent extends Equatable {
4+
const HomeEvent();
5+
6+
@override
7+
List<Object?> get props => [];
8+
}
9+
10+
class BottomNavItemPressed extends HomeEvent {
11+
const BottomNavItemPressed({required this.index});
12+
final int index;
13+
14+
@override
15+
List<Object?> get props => [index];
16+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
part of 'home_bloc.dart';
2+
3+
@freezed
4+
class HomeState with _$HomeState {
5+
const factory HomeState({
6+
@Default(FeedScreen()) Widget screen,
7+
@Default(0) int selectedIndex,
8+
}) = _HomeState;
9+
10+
const HomeState._();
11+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_bloc/flutter_bloc.dart';
3+
4+
import '../../data/constants/assets.dart';
5+
import '../../data/constants/colors.dart';
6+
import 'bloc/home_bloc.dart';
7+
import 'widgets/nav_bar_item.dart';
8+
9+
class HomeScreen extends StatelessWidget {
10+
const HomeScreen({Key? key}) : super(key: key);
11+
12+
@override
13+
Widget build(BuildContext context) {
14+
return BlocBuilder<HomeBloc, HomeState>(
15+
builder: (context, state) {
16+
return Scaffold(
17+
body: state.screen,
18+
bottomNavigationBar: Container(
19+
decoration: const BoxDecoration(
20+
color: AppColors.white,
21+
boxShadow: [
22+
BoxShadow(
23+
blurRadius: 16,
24+
color: Color.fromRGBO(193, 193, 193, 0.5),
25+
offset: Offset(0, -4),
26+
),
27+
],
28+
),
29+
child: Row(
30+
mainAxisAlignment: MainAxisAlignment.spaceAround,
31+
children: [
32+
NavBarItem(
33+
label: 'Feed',
34+
isActive: state.selectedIndex == 0,
35+
callback: () {
36+
context
37+
.read<HomeBloc>()
38+
.add(const BottomNavItemPressed(index: 0));
39+
},
40+
icon: AppAssets.feed,
41+
),
42+
NavBarItem(
43+
label: 'Contests',
44+
isActive: state.selectedIndex == 1,
45+
callback: () {
46+
context
47+
.read<HomeBloc>()
48+
.add(const BottomNavItemPressed(index: 1));
49+
},
50+
icon: AppAssets.contest,
51+
),
52+
NavBarItem(
53+
label: 'Search',
54+
isActive: state.selectedIndex == 2,
55+
callback: () {
56+
context
57+
.read<HomeBloc>()
58+
.add(const BottomNavItemPressed(index: 2));
59+
},
60+
icon: AppAssets.search,
61+
),
62+
NavBarItem(
63+
label: 'Profile',
64+
isActive: state.selectedIndex == 3,
65+
callback: () {
66+
context
67+
.read<HomeBloc>()
68+
.add(const BottomNavItemPressed(index: 3));
69+
},
70+
icon: AppAssets.profile,
71+
),
72+
],
73+
),
74+
),
75+
);
76+
},
77+
);
78+
}
79+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_svg/svg.dart';
3+
4+
import '../../../data/constants/colors.dart';
5+
6+
class NavBarItem extends StatelessWidget {
7+
const NavBarItem({
8+
required this.label,
9+
required this.isActive,
10+
required this.callback,
11+
required this.icon,
12+
Key? key,
13+
}) : super(key: key);
14+
final String label;
15+
final String icon;
16+
final bool isActive;
17+
final VoidCallback callback;
18+
19+
@override
20+
Widget build(BuildContext context) {
21+
return InkWell(
22+
onTap: callback,
23+
child: SizedBox(
24+
height: 60,
25+
child: Column(
26+
children: [
27+
Container(
28+
width: 52,
29+
height: 2,
30+
color: isActive ? AppColors.primary : null,
31+
),
32+
const Expanded(child: SizedBox()),
33+
SvgPicture.asset(
34+
icon,
35+
color: isActive ? AppColors.primary : null,
36+
),
37+
const SizedBox(height: 2),
38+
Text(
39+
label,
40+
style: TextStyle(
41+
color: isActive ? AppColors.primary : AppColors.grey1,
42+
fontSize: 12,
43+
),
44+
),
45+
const Expanded(child: SizedBox()),
46+
],
47+
),
48+
),
49+
);
50+
}
51+
}
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 ProfileScreen extends StatelessWidget {
4+
const ProfileScreen({Key? key}) : super(key: key);
5+
6+
@override
7+
Widget build(BuildContext context) {
8+
return const Center(
9+
child: Text('Profile Screen'),
10+
);
11+
}
12+
}

0 commit comments

Comments
 (0)