Skip to content

Commit 2d06292

Browse files
committed
feat: implement loading state and empty state in contests
1 parent 5a5baee commit 2d06292

10 files changed

Lines changed: 214 additions & 46 deletions

File tree

lib/data/constants/assets.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@ class AppAssets {
1010
static const String eyeOff = '$_iconsRoot/eye-off.svg';
1111
static const String lock = '$_iconsRoot/lock.svg';
1212
static const String person = '$_iconsRoot/person.svg';
13+
static const String filter = '$_iconsRoot/filter.svg';
1314

1415
// Images
1516
static const String circle1 = '$_imagesRoot/circle1.svg';
1617
static const String circle2 = '$_imagesRoot/circle2.svg';
1718
static const String triangle = '$_imagesRoot/triangle.svg';
19+
static const String emptyState = '$_imagesRoot/empty_feed.svg';
1820

1921
// Illustrations
2022
static const String contestCardIllustration =
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import 'dart:developer';
2+
3+
import 'package:equatable/equatable.dart';
4+
import 'package:flutter_bloc/flutter_bloc.dart';
5+
import 'package:freezed_annotation/freezed_annotation.dart';
6+
7+
import '../../../domain/models/contest.dart';
8+
import '../../../domain/repositories/cp_repository.dart';
9+
10+
part 'contests_event.dart';
11+
part 'contests_state.dart';
12+
part 'contests_bloc.freezed.dart';
13+
14+
class ContestsBloc extends Bloc<ContestsEvent, ContestsState> {
15+
ContestsBloc() : super(const ContestsState()) {
16+
on<FetchContests>(_fetchContests);
17+
}
18+
19+
void _fetchContests(FetchContests event, Emitter<ContestsState> emit) async {
20+
final contest = await CPRepository.contestList();
21+
log(contest?.ongoing?.length.toString() ?? 'no contest found');
22+
emit(state.copyWith(contest: contest, isLoading: false));
23+
}
24+
25+
void init() {
26+
add(const FetchContests());
27+
}
28+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
part of 'contests_bloc.dart';
2+
3+
abstract class ContestsEvent extends Equatable {
4+
const ContestsEvent();
5+
6+
@override
7+
List<Object?> get props => [];
8+
}
9+
10+
class FetchContests extends ContestsEvent {
11+
const FetchContests();
12+
13+
@override
14+
List<Object?> get props => [];
15+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
part of 'contests_bloc.dart';
2+
3+
@freezed
4+
class ContestsState with _$ContestsState {
5+
const factory ContestsState({
6+
@Default(true) bool isLoading,
7+
Contest? contest,
8+
}) = _ContestsState;
9+
10+
const ContestsState._();
11+
}
Lines changed: 17 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,28 @@
11
import 'package:flutter/material.dart';
2-
import 'package:flutter_screenutil/flutter_screenutil.dart';
3-
import 'package:flutter_svg/svg.dart';
2+
import 'package:flutter_bloc/flutter_bloc.dart';
43

5-
import '../../data/constants/assets.dart';
6-
import '../../data/constants/colors.dart';
4+
import 'bloc/contests_bloc.dart';
5+
import 'widgets/empty_state.dart';
6+
import 'widgets/loading_state.dart';
77

88
class ContestsScreen extends StatelessWidget {
99
const ContestsScreen({Key? key}) : super(key: key);
1010

1111
@override
1212
Widget build(BuildContext context) {
13-
return Column(
14-
children: [
15-
Container(
16-
height: 55.h,
17-
decoration: BoxDecoration(
18-
boxShadow: [
19-
BoxShadow(
20-
blurRadius: 2,
21-
color: AppColors.white.withOpacity(0.15),
22-
offset: const Offset(0, 1),
23-
),
24-
],
25-
),
26-
padding: EdgeInsets.symmetric(horizontal: 17.w),
27-
child: Row(
28-
mainAxisAlignment: MainAxisAlignment.spaceBetween,
29-
children: [
30-
const Text(
31-
'Contest',
32-
style: TextStyle(
33-
fontSize: 22,
34-
fontWeight: FontWeight.w600,
35-
color: Colors.black,
36-
),
37-
),
38-
IconButton(
39-
onPressed: () {},
40-
icon: SvgPicture.asset(AppAssets.search),
41-
)
42-
],
43-
),
44-
),
45-
],
13+
return BlocProvider(
14+
create: (context) => ContestsBloc()..init(),
15+
child: BlocBuilder<ContestsBloc, ContestsState>(
16+
builder: (context, state) {
17+
if (state.isLoading) {
18+
return const LoadingState();
19+
}
20+
if (state.contest == null) {
21+
return const EmptyState();
22+
}
23+
return Container();
24+
},
25+
),
4626
);
4727
}
4828
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_svg/flutter_svg.dart';
3+
4+
import '../../../data/constants/assets.dart';
5+
import '../../../data/constants/colors.dart';
6+
7+
class ContestHeader extends StatelessWidget {
8+
const ContestHeader({Key? key}) : super(key: key);
9+
10+
@override
11+
Widget build(BuildContext context) {
12+
return AppBar(
13+
automaticallyImplyLeading: false,
14+
backgroundColor: AppColors.white,
15+
title: const Text(
16+
'Contest',
17+
style: TextStyle(
18+
fontSize: 22,
19+
fontWeight: FontWeight.w600,
20+
color: Colors.black,
21+
),
22+
),
23+
actions: [
24+
IconButton(
25+
onPressed: () {},
26+
icon: SvgPicture.asset(AppAssets.filter),
27+
),
28+
],
29+
);
30+
}
31+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_screenutil/flutter_screenutil.dart';
3+
import 'package:flutter_svg/flutter_svg.dart';
4+
5+
import '../../../data/constants/assets.dart';
6+
import '../../../data/constants/colors.dart';
7+
8+
class EmptyState extends StatelessWidget {
9+
const EmptyState({Key? key}) : super(key: key);
10+
11+
@override
12+
Widget build(BuildContext context) {
13+
return Column(
14+
mainAxisAlignment: MainAxisAlignment.center,
15+
children: <Widget>[
16+
SvgPicture.asset(AppAssets.emptyState),
17+
Container(
18+
width: double.infinity,
19+
padding: EdgeInsets.all(25.r),
20+
child: const Text(
21+
'No contests found, please adjust your filters!',
22+
textAlign: TextAlign.center,
23+
style: TextStyle(
24+
color: AppColors.grey1,
25+
),
26+
),
27+
),
28+
],
29+
);
30+
}
31+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_screenutil/flutter_screenutil.dart';
3+
4+
class LoadingState extends StatelessWidget {
5+
const LoadingState({Key? key}) : super(key: key);
6+
7+
@override
8+
Widget build(BuildContext context) {
9+
return ListView.builder(
10+
shrinkWrap: true,
11+
itemCount: 8,
12+
physics: const AlwaysScrollableScrollPhysics(),
13+
itemBuilder: (context, index) {
14+
return Row(
15+
mainAxisSize: MainAxisSize.min,
16+
crossAxisAlignment: CrossAxisAlignment.start,
17+
children: <Widget>[
18+
const Padding(
19+
padding: EdgeInsets.fromLTRB(25, 15, 15, 0),
20+
child: CircleAvatar(
21+
backgroundColor: Color(0xFFE5E5E5),
22+
radius: 18,
23+
),
24+
),
25+
Column(
26+
crossAxisAlignment: CrossAxisAlignment.start,
27+
mainAxisSize: MainAxisSize.min,
28+
children: <Widget>[
29+
Container(
30+
margin: const EdgeInsets.fromLTRB(0, 15, 0, 10),
31+
width: 150.w,
32+
decoration: BoxDecoration(
33+
borderRadius: BorderRadius.circular(2),
34+
color: const Color(0xFFE5E5E5),
35+
),
36+
height: 14,
37+
),
38+
Container(
39+
margin: const EdgeInsets.fromLTRB(0, 0, 0, 10),
40+
width: 250.w,
41+
height: 20,
42+
decoration: BoxDecoration(
43+
borderRadius: BorderRadius.circular(2),
44+
color: const Color(0xFFE5E5E5),
45+
),
46+
),
47+
Container(
48+
margin: const EdgeInsets.fromLTRB(0, 0, 0, 15),
49+
width: 250.w,
50+
height: 20,
51+
decoration: BoxDecoration(
52+
borderRadius: BorderRadius.circular(2),
53+
color: const Color(0xFFE5E5E5),
54+
),
55+
)
56+
],
57+
)
58+
],
59+
);
60+
},
61+
);
62+
}
63+
}

lib/presentation/home/home_screen.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
33

44
import '../../data/constants/assets.dart';
55
import '../../data/constants/colors.dart';
6+
import '../contests/widgets/contest_header.dart';
67
import 'bloc/home_bloc.dart';
78
import 'widgets/nav_bar_item.dart';
89

@@ -15,6 +16,12 @@ class HomeScreen extends StatelessWidget {
1516
builder: (context, state) {
1617
return SafeArea(
1718
child: Scaffold(
19+
appBar: state.selectedIndex == 1
20+
? const PreferredSize(
21+
preferredSize: Size.fromHeight(kToolbarHeight),
22+
child: ContestHeader(),
23+
)
24+
: null,
1825
body: state.screen,
1926
bottomNavigationBar: Container(
2027
decoration: const BoxDecoration(

pubspec.lock

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ packages:
259259
name: firebase_crashlytics
260260
url: "https://pub.dartlang.org"
261261
source: hosted
262-
version: "2.5.0"
262+
version: "2.5.1"
263263
firebase_crashlytics_platform_interface:
264264
dependency: transitive
265265
description:
@@ -428,7 +428,7 @@ packages:
428428
name: http_multi_server
429429
url: "https://pub.dartlang.org"
430430
source: hosted
431-
version: "3.0.1"
431+
version: "3.2.0"
432432
http_parser:
433433
dependency: transitive
434434
description:
@@ -547,7 +547,7 @@ packages:
547547
name: package_info_plus
548548
url: "https://pub.dartlang.org"
549549
source: hosted
550-
version: "1.3.0"
550+
version: "1.3.1"
551551
package_info_plus_linux:
552552
dependency: transitive
553553
description:
@@ -610,7 +610,7 @@ packages:
610610
name: path_provider
611611
url: "https://pub.dartlang.org"
612612
source: hosted
613-
version: "2.0.8"
613+
version: "2.0.9"
614614
path_provider_android:
615615
dependency: transitive
616616
description:
@@ -715,14 +715,14 @@ packages:
715715
name: sentry
716716
url: "https://pub.dartlang.org"
717717
source: hosted
718-
version: "6.2.2"
718+
version: "6.3.0"
719719
sentry_flutter:
720720
dependency: "direct main"
721721
description:
722722
name: sentry_flutter
723723
url: "https://pub.dartlang.org"
724724
source: hosted
725-
version: "6.2.2"
725+
version: "6.3.0"
726726
shelf:
727727
dependency: transitive
728728
description:
@@ -916,14 +916,14 @@ packages:
916916
name: win32
917917
url: "https://pub.dartlang.org"
918918
source: hosted
919-
version: "2.3.6"
919+
version: "2.4.0"
920920
xdg_directories:
921921
dependency: transitive
922922
description:
923923
name: xdg_directories
924924
url: "https://pub.dartlang.org"
925925
source: hosted
926-
version: "0.2.0"
926+
version: "0.2.0+1"
927927
xml:
928928
dependency: transitive
929929
description:
@@ -939,5 +939,5 @@ packages:
939939
source: hosted
940940
version: "3.1.0"
941941
sdks:
942-
dart: ">=2.14.0 <3.0.0"
942+
dart: ">=2.15.0 <3.0.0"
943943
flutter: ">=2.5.0"

0 commit comments

Comments
 (0)