feat:browse bloc done
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
abstract class AppLocaleKeys {
|
||||
///Storage keys
|
||||
static const String language = 'language';
|
||||
static const String browseSearchHistory = 'browse-search-history';
|
||||
|
||||
static const String fontBold = "fontBold";
|
||||
static const String fontMedium = "fontMedium";
|
||||
|
||||
@@ -13,6 +13,8 @@ import 'package:get_it/get_it.dart' as _i174;
|
||||
import 'package:injectable/injectable.dart' as _i526;
|
||||
|
||||
import '../../feature/basket/presentation/blocs/basket_bloc.dart' as _i728;
|
||||
import '../../feature/browse/presentation/blocs/browse_bloc/browse_bloc.dart'
|
||||
as _i991;
|
||||
import '../../feature/common/presentation/blocs/language_bloc/language_bloc.dart'
|
||||
as _i942;
|
||||
import '../../feature/home/presentation/blocs/home_bloc/home_bloc.dart'
|
||||
@@ -33,9 +35,10 @@ extension GetItInjectableX on _i174.GetIt {
|
||||
}) {
|
||||
final gh = _i526.GetItHelper(this, environment, environmentFilter);
|
||||
gh.factory<_i1007.HomeBloc>(() => _i1007.HomeBloc());
|
||||
gh.factory<_i728.BasketBloc>(() => _i728.BasketBloc());
|
||||
gh.factory<_i991.BrowseBloc>(() => _i991.BrowseBloc());
|
||||
gh.factory<_i580.MainBloc>(() => _i580.MainBloc());
|
||||
gh.factory<_i311.SplashBloc>(() => _i311.SplashBloc());
|
||||
gh.factory<_i728.BasketBloc>(() => _i728.BasketBloc());
|
||||
gh.singleton<_i306.StorageService>(() => _i306.StorageService());
|
||||
gh.singleton<_i152.AppRoutes>(() => _i152.AppRoutes());
|
||||
gh.factory<_i942.LanguageBloc>(
|
||||
|
||||
@@ -12,6 +12,16 @@ class StorageService {
|
||||
_sharedPreference.setString(key, value);
|
||||
}
|
||||
|
||||
void setStringList({required String key, required String value}) {
|
||||
final oldList = _sharedPreference.getStringList(key);
|
||||
final newList = oldList?..add(value);
|
||||
_sharedPreference.setStringList(key, newList ?? []);
|
||||
}
|
||||
|
||||
List<String> getStringList({required String key}) {
|
||||
return _sharedPreference.getStringList(key) ?? [];
|
||||
}
|
||||
|
||||
String? getString({required String key}) {
|
||||
return _sharedPreference.getString(key);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
export 'presentation/pages/browse_page/browse_page.dart';
|
||||
export 'package:food_delivery_client/feature/browse/presentation/pages/browse_page/widgets/w_browse_body.dart';
|
||||
export 'package:food_delivery_client/feature/browse/presentation/pages/browse_page/widgets/w_browse_item.dart';
|
||||
export "presentation/blocs/browse_bloc/browse_bloc.dart";
|
||||
export 'package:food_delivery_client/feature/browse/presentation/pages/browse_page/widgets/w_all_categories_skeletonizer.dart';
|
||||
export 'package:food_delivery_client/feature/browse/presentation/pages/browse_page/widgets/w_browse_skeletonizer.dart';
|
||||
export 'package:food_delivery_client/feature/browse/presentation/pages/browse_page/widgets/w_all_categories.dart';
|
||||
export 'package:food_delivery_client/feature/browse/presentation/pages/browse_page/widgets/w_top_categories.dart';
|
||||
export 'package:food_delivery_client/feature/common/presentation/widgets/app_text_form_field.dart';
|
||||
export 'package:food_delivery_client/feature/browse/presentation/pages/browse_page/widgets/w_top_categories_skeletonizer.dart';
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
import 'package:food_delivery_client/food_delivery_client.dart';
|
||||
|
||||
part 'browse_event.dart';
|
||||
|
||||
part 'browse_state.dart';
|
||||
|
||||
part 'browse_bloc.freezed.dart';
|
||||
|
||||
@injectable
|
||||
class BrowseBloc extends Bloc<BrowseEvent, BrowseState> {
|
||||
BrowseBloc() : super(const BrowseState()) {
|
||||
on<_GetTopCategories>(_onGetTopCategories);
|
||||
on<_GetAllCategories>(_onGetAllCategories);
|
||||
on<_GetSearchHistory>(_onGetSearchHistory);
|
||||
on<_FocusChanged>(_onFocusChanged);
|
||||
}
|
||||
|
||||
Future<void> _onGetTopCategories(
|
||||
_GetTopCategories event,
|
||||
Emitter<BrowseState> emit,
|
||||
) async {
|
||||
emit(state.copyWith(topCategorySt: RequestStatus.loading));
|
||||
await Future.delayed(TimeDelayConst.duration3);
|
||||
emit(state.copyWith(topCategorySt: RequestStatus.loaded));
|
||||
}
|
||||
|
||||
Future<void> _onGetAllCategories(
|
||||
_GetAllCategories event,
|
||||
Emitter<BrowseState> emit,
|
||||
) async {
|
||||
emit(state.copyWith(allCategorySt: RequestStatus.loading));
|
||||
await Future.delayed(TimeDelayConst.duration3);
|
||||
emit(state.copyWith(allCategorySt: RequestStatus.loaded));
|
||||
}
|
||||
|
||||
Future<void> _onGetSearchHistory(
|
||||
_GetSearchHistory event,
|
||||
Emitter<BrowseState> emit,
|
||||
) async {
|
||||
emit(state.copyWith(searchHistorySt: RequestStatus.loading));
|
||||
await Future.delayed(TimeDelayConst.duration3);
|
||||
emit(state.copyWith(searchHistorySt: RequestStatus.loading));
|
||||
}
|
||||
|
||||
void _onFocusChanged(_FocusChanged event, Emitter<BrowseState> emit) {
|
||||
emit(state.copyWith(isActive: event.isActive ?? !(state.isActive)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
part of 'browse_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class BrowseEvent with _$BrowseEvent {
|
||||
const factory BrowseEvent.started() = _Started;
|
||||
|
||||
const factory BrowseEvent.getTopCategories() = _GetTopCategories;
|
||||
|
||||
const factory BrowseEvent.getAllCategories() = _GetAllCategories;
|
||||
|
||||
const factory BrowseEvent.getSearchHistory() = _GetSearchHistory;
|
||||
|
||||
const factory BrowseEvent.focusChanged(bool? isActive) = _FocusChanged;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
part of 'browse_bloc.dart';
|
||||
|
||||
@freezed
|
||||
abstract class BrowseState with _$BrowseState {
|
||||
const factory BrowseState({
|
||||
@Default(RequestStatus.initial) RequestStatus topCategorySt,
|
||||
@Default(RequestStatus.initial) RequestStatus allCategorySt,
|
||||
@Default(RequestStatus.initial) RequestStatus searchHistorySt,
|
||||
@Default([]) List<String> searchHistory,
|
||||
@Default(false) bool isActive,
|
||||
}) = _BrowseState;
|
||||
}
|
||||
@@ -6,8 +6,11 @@ class BrowsePage extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return WLayout(
|
||||
child: Scaffold(body:WBrowseBody() ),
|
||||
return BlocProvider(
|
||||
create: (context) => sl<BrowseBloc>()
|
||||
..add(BrowseEvent.getTopCategories())
|
||||
..add(BrowseEvent.getAllCategories()),
|
||||
child: WLayout(child: Scaffold(body: WBrowseBody())),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,25 @@
|
||||
|
||||
import '../../../../../../food_delivery_client.dart';
|
||||
|
||||
class WAllCategories extends StatelessWidget {
|
||||
const WAllCategories({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<BrowseBloc, BrowseState>(
|
||||
builder: (context, state) {
|
||||
if (state.allCategorySt.isLoaded()) {
|
||||
return WAllCategoriesBody();
|
||||
}
|
||||
return WAllCategoriesSkeletonizer();
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class WAllCategoriesBody extends StatelessWidget {
|
||||
const WAllCategoriesBody({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
|
||||
import '../../../../../../food_delivery_client.dart';
|
||||
|
||||
class WAllCategoriesSkeletonizer extends StatelessWidget {
|
||||
const WAllCategoriesSkeletonizer({
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Skeletonizer(
|
||||
enabled: true,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
25.verticalSpace,
|
||||
Text(
|
||||
context.loc.allCategories,
|
||||
style: AppTextStyles.size24Medium.copyWith(height: 36 / 24),
|
||||
),
|
||||
11.verticalSpace,
|
||||
GridView.builder(
|
||||
itemCount: 10,
|
||||
shrinkWrap: true,
|
||||
padding: EdgeInsets.zero,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 2,
|
||||
mainAxisSpacing: 15,
|
||||
crossAxisSpacing: 10,
|
||||
mainAxisExtent: 140,
|
||||
),
|
||||
itemBuilder: (context, index) {
|
||||
return WBrowseSkeletonizerItem();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,44 @@
|
||||
import 'package:food_delivery_client/feature/browse/presentation/pages/browse_page/widgets/w_all_categories.dart';
|
||||
import 'package:food_delivery_client/feature/browse/presentation/pages/browse_page/widgets/w_top_categories.dart';
|
||||
import 'package:food_delivery_client/feature/common/presentation/widgets/app_text_form_field.dart';
|
||||
|
||||
import '../../../../../../food_delivery_client.dart';
|
||||
|
||||
class WBrowseBody extends StatelessWidget {
|
||||
class WBrowseBody extends StatefulWidget {
|
||||
const WBrowseBody({super.key});
|
||||
|
||||
@override
|
||||
State<WBrowseBody> createState() => _WBrowseBodyState();
|
||||
}
|
||||
|
||||
class _WBrowseBodyState extends State<WBrowseBody> {
|
||||
late FocusNode _focusNode;
|
||||
late TextEditingController _controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_controller = TextEditingController();
|
||||
_focusNode = FocusNode();
|
||||
_focusNode.addListener(() {
|
||||
context.read<BrowseBloc>().add(BrowseEvent.focusChanged(true));
|
||||
});
|
||||
super.initState();
|
||||
}
|
||||
|
||||
void listener() {
|
||||
_focusNode.addListener(() {
|
||||
log("${_focusNode.hasFocus}");
|
||||
setState(() {});
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
_focusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<BrowseBloc, BrowseState>(
|
||||
builder: (context, state) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@@ -18,26 +48,70 @@ class WBrowseBody extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
10.verticalSpace,
|
||||
AppTextFormField(
|
||||
controller: TextEditingController(),
|
||||
Row(
|
||||
spacing: 15,
|
||||
children: [
|
||||
/*
|
||||
InkWell(
|
||||
onTap: () {},
|
||||
borderRadius: AppUtils.kBorderRadius25,
|
||||
child: Ink(
|
||||
height: 44,
|
||||
width: 44,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.cEEEEEE,
|
||||
borderRadius: AppUtils.kBorderRadius25,
|
||||
),
|
||||
child: SizedBox(
|
||||
height: 44,
|
||||
width: 44,
|
||||
child: SvgPicture.asset(
|
||||
AppIcons.icBack,
|
||||
height: 20,
|
||||
width: 20,
|
||||
).paddingAll(10),
|
||||
),
|
||||
),
|
||||
),
|
||||
*/
|
||||
Expanded(
|
||||
child: AppTextFormField(
|
||||
focusNode: _focusNode,
|
||||
controller: _controller,
|
||||
prefixIcon: SvgPicture.asset(AppIcons.icSearch),
|
||||
hintText: context.loc.categoriesShort,
|
||||
hintTextStyle: AppTextStyles.size16Medium.copyWith(
|
||||
color: AppColors.c660000
|
||||
color: AppColors.c660000,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
15.verticalSpace,
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: RefreshIndicator.adaptive(
|
||||
onRefresh: () async {
|
||||
context.read<BrowseBloc>()
|
||||
..add(BrowseEvent.getTopCategories())
|
||||
..add(BrowseEvent.getAllCategories());
|
||||
},
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [WTopCategories(), WAllCategories(), 40.verticalSpace],
|
||||
children: [
|
||||
WTopCategories(),
|
||||
WAllCategories(),
|
||||
40.verticalSpace,
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
).paddingSymmetric(horizontal: 16);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
import '../../../../../../food_delivery_client.dart';
|
||||
|
||||
class WBrowseSkeletonizerItem extends StatelessWidget {
|
||||
const WBrowseSkeletonizerItem({
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Bounceable(
|
||||
onTap: () {},
|
||||
child: Ink(
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.cFFFFFF,
|
||||
borderRadius: AppUtils.kBorderRadius15,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: AppUtils.kBorderRadiusTop15,
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: AppLocaleKeys.foodImageUrl,
|
||||
width: context.w,
|
||||
height: 96,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: context.w,
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: AppUtils.kBorderRadiusBottom15,
|
||||
border: Border.all(
|
||||
color: AppColors.cE8E8E8,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
"Restaurant Rewards",
|
||||
textAlign: TextAlign.center,
|
||||
style: AppTextStyles.size16Regular.copyWith(
|
||||
height: 20 / 16,
|
||||
),
|
||||
).paddingSymmetric(horizontal: 30),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,22 @@ import '../../../../../../food_delivery_client.dart';
|
||||
class WTopCategories extends StatelessWidget {
|
||||
const WTopCategories({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<BrowseBloc, BrowseState>(
|
||||
builder: (context, state) {
|
||||
if (state.topCategorySt.isLoaded()) {
|
||||
return WTopCategoriesBody();
|
||||
}
|
||||
return WTopCategoriesSkeletonizer();
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class WTopCategoriesBody extends StatelessWidget {
|
||||
const WTopCategoriesBody({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
@@ -15,7 +31,7 @@ class WTopCategories extends StatelessWidget {
|
||||
),
|
||||
11.verticalSpace,
|
||||
GridView.builder(
|
||||
itemCount:6,
|
||||
itemCount: 6,
|
||||
shrinkWrap: true,
|
||||
padding: EdgeInsets.zero,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
|
||||
import '../../../../../../food_delivery_client.dart';
|
||||
|
||||
class WTopCategoriesSkeletonizer extends StatelessWidget {
|
||||
const WTopCategoriesSkeletonizer({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Skeletonizer(
|
||||
enabled: true,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
context.loc.topCategories,
|
||||
style: AppTextStyles.size24Medium.copyWith(height: 36 / 24),
|
||||
),
|
||||
11.verticalSpace,
|
||||
GridView.builder(
|
||||
itemCount: 6,
|
||||
shrinkWrap: true,
|
||||
padding: EdgeInsets.zero,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 2,
|
||||
mainAxisSpacing: 15,
|
||||
crossAxisSpacing: 10,
|
||||
mainAxisExtent: 140,
|
||||
),
|
||||
itemBuilder: (context, index) {
|
||||
return WBrowseSkeletonizerItem();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ class AppTextFormField extends StatelessWidget {
|
||||
this.obscureText = false,
|
||||
required this.controller,
|
||||
this.prefixIcon,
|
||||
this.prefixSvgPath,
|
||||
this.prefixSvgPath, this.focusNode,
|
||||
});
|
||||
|
||||
final int? maxLines;
|
||||
@@ -36,6 +36,7 @@ class AppTextFormField extends StatelessWidget {
|
||||
final TextStyle? hintTextStyle;
|
||||
late final Widget? prefixIcon;
|
||||
final String? prefixSvgPath;
|
||||
final FocusNode? focusNode;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -45,6 +46,7 @@ class AppTextFormField extends StatelessWidget {
|
||||
maxLines: maxLines ?? 1,
|
||||
minLines: minLines ?? 1,
|
||||
onChanged: onChanged,
|
||||
focusNode: focusNode,
|
||||
inputFormatters: inputFormatters,
|
||||
keyboardType: keyBoardType,
|
||||
style: textStyle ?? AppTextStyles.size16Regular,
|
||||
|
||||
Reference in New Issue
Block a user