handle categories in mobile and web .
This commit is contained in:
parent
5144f1c446
commit
552f962f4f
|
|
@ -1,14 +1,19 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:proxibuy/presentation/providers/category/cubit/categories_children_cubit.dart';
|
||||||
|
import 'package:proxibuy/presentation/providers/category/cubit/categories_cubit.dart';
|
||||||
import 'package:proxibuy/presentation/providers/category/cubit/category_cubit.dart';
|
import 'package:proxibuy/presentation/providers/category/cubit/category_cubit.dart';
|
||||||
import 'package:proxibuy/presentation/providers/user_info_cubit.dart';
|
import 'package:proxibuy/presentation/providers/user_info_cubit.dart';
|
||||||
import 'package:proxibuy/presentation/ui/screens/auth/auth_page.dart';
|
import 'package:proxibuy/presentation/ui/screens/auth/auth_page.dart';
|
||||||
import 'package:proxibuy/presentation/ui/screens/categories/categories_page.dart';
|
import 'package:proxibuy/presentation/ui/screens/home/screens/categories_screen.dart';
|
||||||
import 'package:proxibuy/presentation/ui/screens/home/explore_screen.dart';
|
import 'package:proxibuy/presentation/ui/screens/home/screens/explore_screen.dart';
|
||||||
import 'package:proxibuy/presentation/ui/screens/home/home_page.dart';
|
import 'package:proxibuy/presentation/ui/screens/home/home_page.dart';
|
||||||
import 'package:proxibuy/presentation/ui/screens/home/home_screen.dart';
|
import 'package:proxibuy/presentation/ui/screens/home/screens/home_screen.dart';
|
||||||
import 'package:proxibuy/presentation/ui/screens/home/setting_screen.dart';
|
import 'package:proxibuy/presentation/ui/screens/home/screens/setting_screen.dart';
|
||||||
|
import 'package:proxibuy/presentation/ui/theme/responsive.dart';
|
||||||
import 'package:proxibuy/presentation/ui/widgets/navigations/drop_down_demo2.dart';
|
import 'package:proxibuy/presentation/ui/widgets/navigations/drop_down_demo2.dart';
|
||||||
|
|
||||||
class AppRouter {
|
class AppRouter {
|
||||||
|
|
@ -18,7 +23,7 @@ class AppRouter {
|
||||||
static final product = '/product';
|
static final product = '/product';
|
||||||
static final categories = '/categories';
|
static final categories = '/categories';
|
||||||
|
|
||||||
static List<String> home = [initial, explore, setting];
|
static List<String> home = [initial, explore, setting, categories];
|
||||||
|
|
||||||
static final GlobalKey<NavigatorState> navigatorKey =
|
static final GlobalKey<NavigatorState> navigatorKey =
|
||||||
GlobalKey<NavigatorState>();
|
GlobalKey<NavigatorState>();
|
||||||
|
|
@ -85,20 +90,49 @@ class AppRouter {
|
||||||
return DropDownDemo3();
|
return DropDownDemo3();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
GoRoute(
|
|
||||||
path: '$categories/:id',
|
|
||||||
builder: (BuildContext context, GoRouterState state) {
|
|
||||||
final id = state.pathParameters['id']!;
|
|
||||||
return BlocProvider<CategoryCubit>(
|
|
||||||
create: (context) => CategoryCubit()..getCategory(id),
|
|
||||||
child: CategoriesPage(
|
|
||||||
id: id,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
|
StatefulShellBranch(routes: [
|
||||||
|
GoRoute(
|
||||||
|
path: categories,
|
||||||
|
redirect: (context, state) {
|
||||||
|
if (Responsive(context).isDesktop()) {
|
||||||
|
return initial;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
builder: (BuildContext context, GoRouterState state) {
|
||||||
|
StreamSubscription? categoriesSubscription;
|
||||||
|
|
||||||
|
String? id = state.uri.queryParameters['id'];
|
||||||
|
if (id != null) {
|
||||||
|
catId.value = id;
|
||||||
|
context.read<CategoriesChildrenCubit>().resetPagination();
|
||||||
|
context
|
||||||
|
.read<CategoriesChildrenCubit>()
|
||||||
|
.getAllChildCategories(id);
|
||||||
|
} else {
|
||||||
|
categoriesSubscription =
|
||||||
|
context.read<CategoriesCubit>().stream.listen(
|
||||||
|
(state) {
|
||||||
|
if (state is CategoriesLoaded) {
|
||||||
|
if (state.categories.isNotEmpty) {
|
||||||
|
id = state.categories.first.id;
|
||||||
|
catId.value = id;
|
||||||
|
// ignore: use_build_context_synchronously
|
||||||
|
context
|
||||||
|
.read<CategoriesChildrenCubit>()
|
||||||
|
.getAllChildCategories(id ?? '');
|
||||||
|
categoriesSubscription?.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return CategoriesScreen();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]),
|
||||||
StatefulShellBranch(routes: [
|
StatefulShellBranch(routes: [
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: explore,
|
path: explore,
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ class ApiService {
|
||||||
enabled: kDebugMode,
|
enabled: kDebugMode,
|
||||||
));
|
));
|
||||||
setAuthToken(
|
setAuthToken(
|
||||||
'eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJheC1zX3N3Tm5fU1hDTVkzWFowSDVKekNhQ0psVXh6bmZ0WHBxSk1YUEF3In0.eyJleHAiOjE3Mzk5NzkwNDUsImlhdCI6MTczOTk0MzA0NSwianRpIjoiMzY2NDllZWQtNTBiNy00ZWYyLWIyNmUtOTcxZDUwODBhODc1IiwiaXNzIjoiaHR0cHM6Ly9rZXljbG9hay5saWFyYS5ydW4vcmVhbG1zL2xiYSIsImF1ZCI6ImFjY291bnQiLCJzdWIiOiJmMzljODIxNi0zODhhLTQ0ZTEtODVhOC00Zjk5NmU2NmU2MDQiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJmcm9udGVuZCIsInNpZCI6IjcwZDlhNDhmLTcxMDktNGYxNi1hNTQ5LTVmNjE3MDk4ZTJmMiIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiaHR0cHM6Ly9sYmEtYXBpLmxpYXJhLnJ1bi8qIiwiaHR0cDovL2xvY2FsaG9zdDozMDAwLyoiLCIvKiJdLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsiZGVmYXVsdC1yb2xlcy1sYmEiLCJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19LCJmcm9udGVuZCI6eyJyb2xlcyI6WyJzaG9wIiwidXNlciJdfX0sInNjb3BlIjoib3BlbmlkIGVtYWlsIHByb2ZpbGUiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwibmFtZSI6ImRlbW8gZGVtbyIsInByZWZlcnJlZF91c2VybmFtZSI6ImRlbW8iLCJnaXZlbl9uYW1lIjoiZGVtbyIsImZhbWlseV9uYW1lIjoiZGVtbyIsImVtYWlsIjoiZGVtb0BnbWFpbC5jb20ifQ.H3MssiP94FiWyc7FqfoSK7Zt58VOZmunM1D-wrseDiTQF2lFIfCMYbWkKv1ko8hn-zn-1ExV_6auFCNS0C_wTyFbGq_IHwYQr9nGqji_cr4dum19doASpfZRQiR_oR5RM96Ht5lV3nY_X7o-ksJEiRDOHUZ-xmDLkxhGWfeTO90DXYWv_S39mS55R7SsQz7PI83B7ya9qgp-5GND_oY3iNjDYVTI46EQuGOTiNyLgUrRk64IFy4Bbhp-EVj7QhGwkDEOosAytzE5aqW98-1GUSfUS77P36Ln0olQEb_uYed8EDkdauAIPN-iN8Eg4q7QmT-fpBCP61dcy04FRfTzPw');
|
'eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJheC1zX3N3Tm5fU1hDTVkzWFowSDVKekNhQ0psVXh6bmZ0WHBxSk1YUEF3In0.eyJleHAiOjE3NDAwNjQ5NDcsImlhdCI6MTc0MDAyODk0NywianRpIjoiNDVhYTQ0YWItYTEyMC00N2M3LWIyMWUtNjExNDllMWZlM2EyIiwiaXNzIjoiaHR0cHM6Ly9rZXljbG9hay5saWFyYS5ydW4vcmVhbG1zL2xiYSIsImF1ZCI6ImFjY291bnQiLCJzdWIiOiJmMzljODIxNi0zODhhLTQ0ZTEtODVhOC00Zjk5NmU2NmU2MDQiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJmcm9udGVuZCIsInNpZCI6ImEwNjUwMmU3LTY4MzItNDVhNC04MmUwLTdhZWI4ODBlZTc5ZiIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiaHR0cHM6Ly9sYmEtYXBpLmxpYXJhLnJ1bi8qIiwiaHR0cDovL2xvY2FsaG9zdDozMDAwLyoiLCIvKiJdLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsiZGVmYXVsdC1yb2xlcy1sYmEiLCJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19LCJmcm9udGVuZCI6eyJyb2xlcyI6WyJzaG9wIiwidXNlciJdfX0sInNjb3BlIjoib3BlbmlkIGVtYWlsIHByb2ZpbGUiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwibmFtZSI6ImRlbW8gZGVtbyIsInByZWZlcnJlZF91c2VybmFtZSI6ImRlbW8iLCJnaXZlbl9uYW1lIjoiZGVtbyIsImZhbWlseV9uYW1lIjoiZGVtbyIsImVtYWlsIjoiZGVtb0BnbWFpbC5jb20ifQ.iwAMzwyuQu9BkNXA65u8XfZIYoGtGvQ99qpCwTCPLDfe2DFZU_1wcOu5TV_7My80UHifzLR587CPGH1xwlJmD1JFtrEh0wk_sBe0iYKOmiz7OhFCLUNAuLkV5dvwYPfqyzPFYQPe8F0QdnK9107pF-15uyjn8w1MLfSE4uCRtc8Arh43WeZqoYALlLkHvQgltxvuBE_FXt_AulIBzmrhwDhA_Aw7gS4J05mGAkMAAX1B4mXxB-OCBN-ZPFEAU14YPQPHAjUdKtJ1scC4VYworjaEA3kkx_gYWdfi-o_3YykDlaE6fxOm4yQnFzg2DjJhE_7i8Lsjchc3GrBNzt4UeQ');
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 🔹 Handle GET requests
|
/// 🔹 Handle GET requests
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,8 @@ import 'package:proxibuy/core/gen/assets.gen.dart';
|
||||||
|
|
||||||
class ScreenModel {
|
class ScreenModel {
|
||||||
final String title;
|
final String title;
|
||||||
|
final String route;
|
||||||
final SvgGenImage icon;
|
final SvgGenImage icon;
|
||||||
|
|
||||||
ScreenModel({required this.title, required this.icon});
|
ScreenModel({required this.title, required this.icon, required this.route});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,8 @@ void main() async {
|
||||||
BlocProvider<ThemModeCubit>(create: (context) => ThemModeCubit()),
|
BlocProvider<ThemModeCubit>(create: (context) => ThemModeCubit()),
|
||||||
BlocProvider<CategoriesChildrenCubit>(
|
BlocProvider<CategoriesChildrenCubit>(
|
||||||
create: (context) => CategoriesChildrenCubit()),
|
create: (context) => CategoriesChildrenCubit()),
|
||||||
BlocProvider<CategoriesCubit>(create: (context) => CategoriesCubit()),
|
BlocProvider<CategoriesCubit>(
|
||||||
|
create: (context) => CategoriesCubit()..getAllCategories()),
|
||||||
BlocProvider<UserInfoCubit>(
|
BlocProvider<UserInfoCubit>(
|
||||||
create: (context) => UserInfoCubit()..getUserInfo()),
|
create: (context) => UserInfoCubit()..getUserInfo()),
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -1,124 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:flutter_svg/svg.dart';
|
|
||||||
import 'package:proxibuy/presentation/providers/category/cubit/categories_children_cubit.dart';
|
|
||||||
import 'package:proxibuy/presentation/providers/category/cubit/category_cubit.dart';
|
|
||||||
import 'package:proxibuy/presentation/ui/widgets/default_placeholder.dart';
|
|
||||||
|
|
||||||
class CategoriesPage extends StatefulWidget {
|
|
||||||
final String id;
|
|
||||||
const CategoriesPage({super.key, required this.id});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<CategoriesPage> createState() => _CategoriesPageState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _CategoriesPageState extends State<CategoriesPage> {
|
|
||||||
final ScrollController _scrollController = ScrollController();
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_scrollController.addListener(_onScroll);
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
|
||||||
await context.read<CategoriesChildrenCubit>().resetPagination();
|
|
||||||
if (mounted) {
|
|
||||||
context
|
|
||||||
.read<CategoriesChildrenCubit>()
|
|
||||||
.getAllChildCategories(widget.id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onScroll() {
|
|
||||||
if (_scrollController.position.pixels ==
|
|
||||||
_scrollController.position.maxScrollExtent) {
|
|
||||||
context.read<CategoriesChildrenCubit>().getAllChildCategories(widget.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(title: BlocBuilder<CategoryCubit, CategoryState>(
|
|
||||||
builder: (context, state) {
|
|
||||||
if (state is CategorySuccess) {
|
|
||||||
return Text(state.category.name ?? '...');
|
|
||||||
}
|
|
||||||
return SizedBox();
|
|
||||||
},
|
|
||||||
)),
|
|
||||||
body: BlocBuilder<CategoriesChildrenCubit, CategoriesChildrenState>(
|
|
||||||
builder: (context, state) {
|
|
||||||
if (state is CategoriesChildrenLoaded) {
|
|
||||||
if (state.categories.isEmpty) {
|
|
||||||
return Center(child: Text('Empty'));
|
|
||||||
}
|
|
||||||
return SingleChildScrollView(
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
ListView.builder(
|
|
||||||
// controller: _scrollController,
|
|
||||||
itemCount: state.categories.length,
|
|
||||||
physics: NeverScrollableScrollPhysics(),
|
|
||||||
shrinkWrap: true,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
if (index >= state.categories.length) {
|
|
||||||
return Center(child: CircularProgressIndicator());
|
|
||||||
}
|
|
||||||
final category = state.categories[index];
|
|
||||||
return ListTile(
|
|
||||||
leading: SvgPicture.network(
|
|
||||||
'${state.categories[index].url}',
|
|
||||||
color: Theme.of(context).colorScheme.onSurface,
|
|
||||||
placeholderBuilder: (context) => DefaultPlaceHolder(
|
|
||||||
child: Container(
|
|
||||||
width: 24,
|
|
||||||
height: 24,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
shape: BoxShape.circle, color: Colors.white),
|
|
||||||
)),
|
|
||||||
errorBuilder: (context, error, stackTrace) =>
|
|
||||||
Icon(Icons.category_outlined),
|
|
||||||
),
|
|
||||||
title: Text(category.name ?? ''),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
if (state.isLoading) LinearProgressIndicator()
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else if (state is CategoriesChildrenError) {
|
|
||||||
return Center(child: Text(state.errorMessage!));
|
|
||||||
} else {
|
|
||||||
return ListView.builder(
|
|
||||||
// controller: _scrollController,
|
|
||||||
itemCount: 20,
|
|
||||||
physics: NeverScrollableScrollPhysics(),
|
|
||||||
shrinkWrap: true,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
return DefaultPlaceHolder(
|
|
||||||
child: Container(
|
|
||||||
margin: EdgeInsets.symmetric(vertical: 8),
|
|
||||||
color: Colors.white,
|
|
||||||
child: ListTile(
|
|
||||||
leading: Icon(Icons.abc_outlined),
|
|
||||||
title: Text(''),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_scrollController.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,178 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:proxibuy/core/gen/assets.gen.dart';
|
||||||
|
import 'package:proxibuy/core/routes/app_router.dart';
|
||||||
|
import 'package:proxibuy/core/utils/empty_space.dart';
|
||||||
|
import 'package:proxibuy/data/models/screen_model.dart';
|
||||||
|
import 'package:proxibuy/presentation/providers/them_mode_cubit.dart';
|
||||||
|
import 'package:proxibuy/presentation/ui/theme/theme.dart';
|
||||||
|
import 'package:proxibuy/presentation/ui/widgets/navigations/categories_mega_menu.dart';
|
||||||
|
|
||||||
|
class HomeDeskPage extends StatefulWidget {
|
||||||
|
final Widget child;
|
||||||
|
const HomeDeskPage({super.key, required this.child});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<HomeDeskPage> createState() => _HomeDeskPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _HomeDeskPageState extends State<HomeDeskPage> {
|
||||||
|
int selectedIndex = 0;
|
||||||
|
List<ScreenModel> deskScreens = [
|
||||||
|
ScreenModel(
|
||||||
|
title: 'Home',
|
||||||
|
icon: Assets.icon.outline.home,
|
||||||
|
route: AppRouter.initial),
|
||||||
|
ScreenModel(
|
||||||
|
title: 'Explore',
|
||||||
|
icon: Assets.icon.outline.map,
|
||||||
|
route: AppRouter.explore),
|
||||||
|
ScreenModel(
|
||||||
|
title: 'Settings',
|
||||||
|
icon: Assets.icon.outline.setting,
|
||||||
|
route: AppRouter.setting),
|
||||||
|
];
|
||||||
|
|
||||||
|
void _onItemTapped(BuildContext context, int index) {
|
||||||
|
setState(() {
|
||||||
|
selectedIndex = index;
|
||||||
|
});
|
||||||
|
switch (index) {
|
||||||
|
case 0:
|
||||||
|
context.go(AppRouter.initial);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
context.go(AppRouter.explore);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
context.go(AppRouter.setting);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
body: Column(
|
||||||
|
children: [
|
||||||
|
navBar(context),
|
||||||
|
Expanded(child: widget.child),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Padding navBar(BuildContext context) {
|
||||||
|
final defaultBorder = OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
borderSide:
|
||||||
|
BorderSide(color: Theme.of(context).colorScheme.surface, width: 2));
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
SelectableText(
|
||||||
|
"Proxibuy",
|
||||||
|
style: Theme.of(context).textTheme.displaySmall,
|
||||||
|
),
|
||||||
|
32.w,
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
...List.generate(
|
||||||
|
deskScreens.length,
|
||||||
|
(index) => Row(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
color: selectedIndex == index
|
||||||
|
? themeColor(context)
|
||||||
|
?.primaryLightSurface
|
||||||
|
.withAlpha(90)
|
||||||
|
: null),
|
||||||
|
child: IconButton(
|
||||||
|
splashRadius: 12,
|
||||||
|
onPressed: () {
|
||||||
|
_onItemTapped(context, index);
|
||||||
|
},
|
||||||
|
icon: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
deskScreens[index].icon.svg(
|
||||||
|
color: selectedIndex == index
|
||||||
|
? Theme.of(context).primaryColor
|
||||||
|
: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.onSurface),
|
||||||
|
12.w,
|
||||||
|
Text(
|
||||||
|
deskScreens[index].title,
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.labelLarge
|
||||||
|
?.copyWith(
|
||||||
|
color: selectedIndex == index
|
||||||
|
? Theme.of(context).primaryColor
|
||||||
|
: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.onSurface),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
24.w
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
CategoriesMegaMenu()
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Flexible(
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
8.w,
|
||||||
|
Flexible(
|
||||||
|
child: Container(
|
||||||
|
constraints: BoxConstraints(maxWidth: 800),
|
||||||
|
child: TextField(
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: 'what are you looking for?',
|
||||||
|
suffixIcon: Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Assets.icon.outline.search.svg(
|
||||||
|
color: Theme.of(context).colorScheme.onSurface,
|
||||||
|
width: 16,
|
||||||
|
height: 16),
|
||||||
|
),
|
||||||
|
enabledBorder: defaultBorder,
|
||||||
|
border: defaultBorder),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
32.w,
|
||||||
|
IconButton(
|
||||||
|
icon: Assets.icon.outline.notificationBing
|
||||||
|
.svg(color: Theme.of(context).colorScheme.onSurface),
|
||||||
|
onPressed: () {},
|
||||||
|
),
|
||||||
|
12.w,
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.brightness_6),
|
||||||
|
onPressed: () {
|
||||||
|
context.read<ThemModeCubit>().changeTheme();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -7,6 +7,7 @@ import 'package:proxibuy/core/routes/app_router.dart';
|
||||||
import 'package:proxibuy/core/utils/empty_space.dart';
|
import 'package:proxibuy/core/utils/empty_space.dart';
|
||||||
import 'package:proxibuy/data/models/screen_model.dart';
|
import 'package:proxibuy/data/models/screen_model.dart';
|
||||||
import 'package:proxibuy/presentation/providers/them_mode_cubit.dart';
|
import 'package:proxibuy/presentation/providers/them_mode_cubit.dart';
|
||||||
|
import 'package:proxibuy/presentation/ui/screens/home/home_desk_page.dart';
|
||||||
import 'package:proxibuy/presentation/ui/theme/responsive.dart';
|
import 'package:proxibuy/presentation/ui/theme/responsive.dart';
|
||||||
import 'package:proxibuy/presentation/ui/theme/theme.dart';
|
import 'package:proxibuy/presentation/ui/theme/theme.dart';
|
||||||
import 'package:proxibuy/presentation/ui/widgets/navigations/categories_mega_menu.dart';
|
import 'package:proxibuy/presentation/ui/widgets/navigations/categories_mega_menu.dart';
|
||||||
|
|
@ -21,24 +22,40 @@ class HomePage extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _HomePageState extends State<HomePage> {
|
class _HomePageState extends State<HomePage> {
|
||||||
int selectedIndex = 0;
|
@override
|
||||||
|
initState() {
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
List<ScreenModel> screens = [
|
List<ScreenModel> screens = [
|
||||||
ScreenModel(title: 'Home', icon: Assets.icon.outline.home),
|
ScreenModel(
|
||||||
ScreenModel(title: 'Explore', icon: Assets.icon.outline.map),
|
title: 'Home',
|
||||||
ScreenModel(title: 'Settings', icon: Assets.icon.outline.setting),
|
icon: Assets.icon.outline.home,
|
||||||
|
route: AppRouter.initial),
|
||||||
|
ScreenModel(
|
||||||
|
title: 'Categories',
|
||||||
|
icon: Assets.icon.outline.search,
|
||||||
|
route: AppRouter.categories),
|
||||||
|
ScreenModel(
|
||||||
|
title: 'Explore',
|
||||||
|
icon: Assets.icon.outline.map,
|
||||||
|
route: AppRouter.explore),
|
||||||
|
ScreenModel(
|
||||||
|
title: 'Settings',
|
||||||
|
icon: Assets.icon.outline.setting,
|
||||||
|
route: AppRouter.setting),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
int _getSelectedIndex(BuildContext context) {
|
||||||
|
final g = GoRouterState.of(context);
|
||||||
|
final String location = g.fullPath.toString();
|
||||||
|
return screens.indexWhere((element) => element.route == location);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Responsive(context).builder(
|
return Responsive(context).builder(
|
||||||
desktop: Scaffold(
|
desktop: HomeDeskPage(child: body()),
|
||||||
body: Column(
|
|
||||||
children: [
|
|
||||||
navBar(context),
|
|
||||||
Expanded(child: body()),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
mobile: Scaffold(
|
mobile: Scaffold(
|
||||||
body: body(),
|
body: body(),
|
||||||
bottomNavigationBar: bottomNavigationBar(context),
|
bottomNavigationBar: bottomNavigationBar(context),
|
||||||
|
|
@ -46,127 +63,14 @@ class _HomePageState extends State<HomePage> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Padding navBar(BuildContext context) {
|
|
||||||
final defaultBorder = OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
borderSide:
|
|
||||||
BorderSide(color: Theme.of(context).colorScheme.surface, width: 2));
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
SelectableText(
|
|
||||||
"Proxibuy",
|
|
||||||
style: Theme.of(context).textTheme.displaySmall,
|
|
||||||
),
|
|
||||||
32.w,
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
...List.generate(
|
|
||||||
screens.length,
|
|
||||||
(index) => Row(
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.circular(12),
|
|
||||||
color: selectedIndex == index
|
|
||||||
? themeColor(context)
|
|
||||||
?.primaryLightSurface
|
|
||||||
.withAlpha(90)
|
|
||||||
: null),
|
|
||||||
child: IconButton(
|
|
||||||
splashRadius: 12,
|
|
||||||
onPressed: () {
|
|
||||||
_onItemTapped(context, index);
|
|
||||||
},
|
|
||||||
icon: Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
|
||||||
children: [
|
|
||||||
screens[index].icon.svg(
|
|
||||||
color: selectedIndex == index
|
|
||||||
? Theme.of(context).primaryColor
|
|
||||||
: Theme.of(context)
|
|
||||||
.colorScheme
|
|
||||||
.onSurface),
|
|
||||||
12.w,
|
|
||||||
Text(
|
|
||||||
screens[index].title,
|
|
||||||
style: Theme.of(context)
|
|
||||||
.textTheme
|
|
||||||
.labelLarge
|
|
||||||
?.copyWith(
|
|
||||||
color: selectedIndex == index
|
|
||||||
? Theme.of(context).primaryColor
|
|
||||||
: Theme.of(context)
|
|
||||||
.colorScheme
|
|
||||||
.onSurface),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
)),
|
|
||||||
),
|
|
||||||
24.w
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
CategoriesMegaMenu()
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Flexible(
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
|
||||||
children: [
|
|
||||||
8.w,
|
|
||||||
Flexible(
|
|
||||||
child: Container(
|
|
||||||
constraints: BoxConstraints(maxWidth: 800),
|
|
||||||
child: TextField(
|
|
||||||
decoration: InputDecoration(
|
|
||||||
hintText: 'what are you looking for?',
|
|
||||||
suffixIcon: Padding(
|
|
||||||
padding: const EdgeInsets.all(8.0),
|
|
||||||
child: Assets.icon.outline.search.svg(
|
|
||||||
color: Theme.of(context).colorScheme.onSurface,
|
|
||||||
width: 16,
|
|
||||||
height: 16),
|
|
||||||
),
|
|
||||||
enabledBorder: defaultBorder,
|
|
||||||
border: defaultBorder),
|
|
||||||
),
|
|
||||||
)),
|
|
||||||
32.w,
|
|
||||||
IconButton(
|
|
||||||
icon: Assets.icon.outline.notificationBing
|
|
||||||
.svg(color: Theme.of(context).colorScheme.onSurface),
|
|
||||||
onPressed: () {},
|
|
||||||
),
|
|
||||||
12.w,
|
|
||||||
IconButton(
|
|
||||||
icon: Icon(Icons.brightness_6),
|
|
||||||
onPressed: () {
|
|
||||||
context.read<ThemModeCubit>().changeTheme();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Padding bottomNavigationBar(BuildContext context) {
|
Padding bottomNavigationBar(BuildContext context) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.all(16.0),
|
padding: const EdgeInsets.all(16.0),
|
||||||
child: BottomNavyBar(
|
child: BottomNavyBar(
|
||||||
selectedIndex: selectedIndex,
|
selectedIndex: _getSelectedIndex(context),
|
||||||
// landscapeLayout: BottomNavigationBarLandscapeLayout.centered,
|
// landscapeLayout: BottomNavigationBarLandscapeLayout.centered,
|
||||||
// showUnselectedLabels: false,
|
// showUnselectedLabels: false,
|
||||||
onItemSelected: (index) => _onItemTapped(context, index),
|
onItemSelected: (index) => _onItemTapped(context, screens[index].route),
|
||||||
backgroundColor: Theme.of(context).colorScheme.surface,
|
backgroundColor: Theme.of(context).colorScheme.surface,
|
||||||
itemCornerRadius: 12,
|
itemCornerRadius: 12,
|
||||||
itemPadding: EdgeInsets.symmetric(horizontal: 16),
|
itemPadding: EdgeInsets.symmetric(horizontal: 16),
|
||||||
|
|
@ -179,7 +83,7 @@ class _HomePageState extends State<HomePage> {
|
||||||
screens.length,
|
screens.length,
|
||||||
(index) => BottomNavyBarItem(
|
(index) => BottomNavyBarItem(
|
||||||
icon: screens[index].icon.svg(
|
icon: screens[index].icon.svg(
|
||||||
color: selectedIndex == index
|
color: _getSelectedIndex(context) == index
|
||||||
? Theme.of(context).primaryColor
|
? Theme.of(context).primaryColor
|
||||||
: Theme.of(context).colorScheme.onSurface),
|
: Theme.of(context).colorScheme.onSurface),
|
||||||
activeColor: Theme.of(context).primaryColor,
|
activeColor: Theme.of(context).primaryColor,
|
||||||
|
|
@ -195,20 +99,7 @@ class _HomePageState extends State<HomePage> {
|
||||||
return widget.child;
|
return widget.child;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onItemTapped(BuildContext context, int index) {
|
void _onItemTapped(BuildContext context, String route) {
|
||||||
setState(() {
|
context.go(route);
|
||||||
selectedIndex = index;
|
|
||||||
});
|
|
||||||
switch (index) {
|
|
||||||
case 0:
|
|
||||||
context.go(AppRouter.initial);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
context.go(AppRouter.explore);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
context.go(AppRouter.setting);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,239 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
import 'package:proxibuy/presentation/providers/category/cubit/categories_children_cubit.dart';
|
||||||
|
import 'package:proxibuy/presentation/providers/category/cubit/categories_cubit.dart';
|
||||||
|
import 'package:proxibuy/presentation/ui/widgets/default_placeholder.dart';
|
||||||
|
|
||||||
|
ValueNotifier<String?> catId = ValueNotifier(null);
|
||||||
|
|
||||||
|
class CategoriesScreen extends StatefulWidget {
|
||||||
|
const CategoriesScreen({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<CategoriesScreen> createState() => _CategoriesScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CategoriesScreenState extends State<CategoriesScreen> {
|
||||||
|
final ScrollController _scrollController = ScrollController();
|
||||||
|
StreamSubscription? _categoriesSubscription;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_scrollController.addListener(_onScroll);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onScroll() {
|
||||||
|
if (_scrollController.position.pixels ==
|
||||||
|
_scrollController.position.maxScrollExtent) {
|
||||||
|
context
|
||||||
|
.read<CategoriesChildrenCubit>()
|
||||||
|
.getAllChildCategories(catId.value ?? '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
body: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: BlocBuilder<CategoriesCubit, CategoriesState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
if (state is CategoriesLoaded) {
|
||||||
|
if (state.categories.isEmpty) {
|
||||||
|
return Center(child: Text('Empty'));
|
||||||
|
}
|
||||||
|
return SingleChildScrollView(
|
||||||
|
child: Container(
|
||||||
|
color: Theme.of(context).colorScheme.surface,
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
ListView.builder(
|
||||||
|
// controller: _scrollController,
|
||||||
|
itemCount: state.categories.length,
|
||||||
|
physics: NeverScrollableScrollPhysics(),
|
||||||
|
shrinkWrap: true,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final category = state.categories[index];
|
||||||
|
return InkWell(
|
||||||
|
onTap: () {
|
||||||
|
context
|
||||||
|
.read<CategoriesChildrenCubit>()
|
||||||
|
.resetPagination();
|
||||||
|
setState(() {
|
||||||
|
catId.value = category.id;
|
||||||
|
});
|
||||||
|
context
|
||||||
|
.read<CategoriesChildrenCubit>()
|
||||||
|
.getAllChildCategories(catId.value ?? '');
|
||||||
|
},
|
||||||
|
child: ValueListenableBuilder(
|
||||||
|
valueListenable: catId,
|
||||||
|
builder: (context, selectedId, _) {
|
||||||
|
return Container(
|
||||||
|
color: selectedId == category.id
|
||||||
|
? Theme.of(context)
|
||||||
|
.scaffoldBackgroundColor
|
||||||
|
: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.surface,
|
||||||
|
child: ListTile(
|
||||||
|
leading: SvgPicture.network(
|
||||||
|
'${category.url}',
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.onSurface,
|
||||||
|
placeholderBuilder: (context) =>
|
||||||
|
DefaultPlaceHolder(
|
||||||
|
child: Container(
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
color: Colors.white),
|
||||||
|
)),
|
||||||
|
errorBuilder: (context, error,
|
||||||
|
stackTrace) =>
|
||||||
|
Icon(Icons.category_outlined),
|
||||||
|
),
|
||||||
|
title: Text(category.name ?? ''),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
if (state.isLoading) LinearProgressIndicator()
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else if (state is CategoriesChildrenError) {
|
||||||
|
return Center(child: Text(state.errorMessage!));
|
||||||
|
} else {
|
||||||
|
return ListView.builder(
|
||||||
|
// controller: _scrollController,
|
||||||
|
itemCount: 20,
|
||||||
|
physics: NeverScrollableScrollPhysics(),
|
||||||
|
shrinkWrap: true,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return DefaultPlaceHolder(
|
||||||
|
child: Container(
|
||||||
|
margin: EdgeInsets.symmetric(vertical: 8),
|
||||||
|
color: Colors.white,
|
||||||
|
child: ListTile(
|
||||||
|
leading: Icon(Icons.abc_outlined),
|
||||||
|
title: Text(''),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
VerticalDivider(),
|
||||||
|
Expanded(
|
||||||
|
flex: 2,
|
||||||
|
child:
|
||||||
|
BlocBuilder<CategoriesChildrenCubit, CategoriesChildrenState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
if (state is CategoriesChildrenLoaded) {
|
||||||
|
if (state.categories.isEmpty) {
|
||||||
|
return Center(child: Text('Empty'));
|
||||||
|
}
|
||||||
|
return SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: TextButton(
|
||||||
|
onPressed: () {},
|
||||||
|
child: Text(
|
||||||
|
'See all',
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.labelLarge
|
||||||
|
?.copyWith(
|
||||||
|
color: Theme.of(context).primaryColor),
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
ListView.builder(
|
||||||
|
// controller: _scrollController,
|
||||||
|
itemCount: state.categories.length,
|
||||||
|
physics: NeverScrollableScrollPhysics(),
|
||||||
|
shrinkWrap: true,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
if (index >= state.categories.length) {
|
||||||
|
return Center(child: CircularProgressIndicator());
|
||||||
|
}
|
||||||
|
final category = state.categories[index];
|
||||||
|
return ListTile(
|
||||||
|
leading: SvgPicture.network(
|
||||||
|
'${state.categories[index].url}',
|
||||||
|
color: Theme.of(context).colorScheme.onSurface,
|
||||||
|
placeholderBuilder: (context) =>
|
||||||
|
DefaultPlaceHolder(
|
||||||
|
child: Container(
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
color: Colors.white),
|
||||||
|
)),
|
||||||
|
errorBuilder: (context, error, stackTrace) =>
|
||||||
|
Icon(Icons.category_outlined),
|
||||||
|
),
|
||||||
|
title: Text(category.name ?? ''),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
if (state.isLoading) LinearProgressIndicator()
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else if (state is CategoriesChildrenError) {
|
||||||
|
return Center(child: Text(state.errorMessage!));
|
||||||
|
} else {
|
||||||
|
return ListView.builder(
|
||||||
|
// controller: _scrollController,
|
||||||
|
itemCount: 20,
|
||||||
|
physics: NeverScrollableScrollPhysics(),
|
||||||
|
shrinkWrap: true,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return DefaultPlaceHolder(
|
||||||
|
child: Container(
|
||||||
|
margin: EdgeInsets.symmetric(vertical: 8),
|
||||||
|
color: Colors.white,
|
||||||
|
child: ListTile(
|
||||||
|
leading: Icon(Icons.abc_outlined),
|
||||||
|
title: Text(''),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_scrollController.dispose();
|
||||||
|
_categoriesSubscription?.cancel();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -26,9 +26,9 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
// WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
context.read<CategoriesCubit>().getAllCategories();
|
// context.read<CategoriesCubit>().getAllCategories();
|
||||||
});
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -590,6 +590,7 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||||
|
|
||||||
Column categories(BuildContext context) {
|
Column categories(BuildContext context) {
|
||||||
return Column(
|
return Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
titleDivider(context, title: 'what\'s on your mind?', top: 16),
|
titleDivider(context, title: 'what\'s on your mind?', top: 16),
|
||||||
BlocBuilder<CategoriesCubit, CategoriesState>(
|
BlocBuilder<CategoriesCubit, CategoriesState>(
|
||||||
|
|
@ -615,7 +616,7 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.go(
|
context.go(
|
||||||
'${AppRouter.categories}/${state.categories[index].id}');
|
'${AppRouter.categories}?id=${state.categories[index].id}');
|
||||||
},
|
},
|
||||||
onHover: (value) {
|
onHover: (value) {
|
||||||
isHovered.value = value;
|
isHovered.value = value;
|
||||||
|
|
@ -1,10 +1,13 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:flutter_svg/svg.dart';
|
||||||
import 'package:proxibuy/core/utils/empty_space.dart';
|
import 'package:proxibuy/core/utils/empty_space.dart';
|
||||||
import 'package:proxibuy/presentation/providers/category/cubit/categories_children_cubit.dart';
|
import 'package:proxibuy/presentation/providers/category/cubit/categories_children_cubit.dart';
|
||||||
import 'package:proxibuy/presentation/providers/category/cubit/categories_cubit.dart';
|
import 'package:proxibuy/presentation/providers/category/cubit/categories_cubit.dart';
|
||||||
|
import 'package:proxibuy/presentation/ui/screens/home/screens/categories_screen.dart';
|
||||||
import 'package:proxibuy/presentation/ui/theme/colors.dart';
|
import 'package:proxibuy/presentation/ui/theme/colors.dart';
|
||||||
import 'package:proxibuy/presentation/ui/theme/theme.dart';
|
import 'package:proxibuy/presentation/ui/theme/theme.dart';
|
||||||
|
import 'package:proxibuy/presentation/ui/widgets/default_placeholder.dart';
|
||||||
|
|
||||||
class CategoriesMegaMenu extends StatefulWidget {
|
class CategoriesMegaMenu extends StatefulWidget {
|
||||||
const CategoriesMegaMenu({super.key});
|
const CategoriesMegaMenu({super.key});
|
||||||
|
|
@ -61,6 +64,7 @@ class _CategoriesMegaMenuState extends State<CategoriesMegaMenu> {
|
||||||
}
|
}
|
||||||
|
|
||||||
OverlayEntry _createMegaMenu() {
|
OverlayEntry _createMegaMenu() {
|
||||||
|
catId.value ??= context.read<CategoriesCubit>().state.categories.first.id;
|
||||||
return OverlayEntry(
|
return OverlayEntry(
|
||||||
builder: (context) => Positioned(
|
builder: (context) => Positioned(
|
||||||
width: 800, // Adjust width of the mega menu
|
width: 800, // Adjust width of the mega menu
|
||||||
|
|
@ -72,121 +76,18 @@ class _CategoriesMegaMenuState extends State<CategoriesMegaMenu> {
|
||||||
child: Material(
|
child: Material(
|
||||||
elevation: 4,
|
elevation: 4,
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: EdgeInsets.all(10),
|
constraints: BoxConstraints(
|
||||||
decoration: BoxDecoration(
|
maxHeight: 600,
|
||||||
borderRadius: BorderRadius.circular(8),
|
),
|
||||||
color: Theme.of(context).colorScheme.surface,
|
padding: EdgeInsets.all(10),
|
||||||
boxShadow: [BoxShadow(color: Colors.black26, blurRadius: 4)],
|
decoration: BoxDecoration(
|
||||||
),
|
borderRadius: BorderRadius.circular(8),
|
||||||
child: Row(
|
color: Theme.of(context).scaffoldBackgroundColor,
|
||||||
children: [
|
boxShadow: [
|
||||||
Expanded(
|
BoxShadow(color: Colors.black26, blurRadius: 4)
|
||||||
child: BlocBuilder<CategoriesCubit, CategoriesState>(
|
],
|
||||||
builder: (context, state) {
|
),
|
||||||
if (state.isLoading && state.categories.isEmpty) {
|
child: CategoriesScreen()),
|
||||||
return Center(child: CircularProgressIndicator());
|
|
||||||
} else if (state.errorMessage != null) {
|
|
||||||
return Center(child: Text(state.errorMessage!));
|
|
||||||
} else {
|
|
||||||
return SingleChildScrollView(
|
|
||||||
child: ValueListenableBuilder(
|
|
||||||
valueListenable: selectedId,
|
|
||||||
builder: (context, id, _) {
|
|
||||||
return Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
...List.generate(
|
|
||||||
context
|
|
||||||
.read<CategoriesCubit>()
|
|
||||||
.state
|
|
||||||
.categories
|
|
||||||
.length,
|
|
||||||
(index) {
|
|
||||||
final cat = context
|
|
||||||
.read<CategoriesCubit>()
|
|
||||||
.state
|
|
||||||
.categories[index];
|
|
||||||
return InkWell(
|
|
||||||
onTap: () {
|
|
||||||
if (cat.id != null) {
|
|
||||||
selectedId.value = cat.id!;
|
|
||||||
context
|
|
||||||
.read<
|
|
||||||
CategoriesChildrenCubit>()
|
|
||||||
.resetPagination();
|
|
||||||
context
|
|
||||||
.read<
|
|
||||||
CategoriesChildrenCubit>()
|
|
||||||
.getAllChildCategories(
|
|
||||||
id!);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: Container(
|
|
||||||
color: cat.id == id
|
|
||||||
? semanticBlue
|
|
||||||
: null,
|
|
||||||
child: _menuItem(
|
|
||||||
cat.name ?? '')));
|
|
||||||
},
|
|
||||||
)
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: BlocBuilder<CategoriesChildrenCubit,
|
|
||||||
CategoriesChildrenState>(
|
|
||||||
builder: (context, state) {
|
|
||||||
if (state.isLoading && state.categories.isEmpty) {
|
|
||||||
return Center(child: CircularProgressIndicator());
|
|
||||||
} else if (state.errorMessage != null) {
|
|
||||||
return Center(child: Text(state.errorMessage!));
|
|
||||||
} else {
|
|
||||||
return NotificationListener<ScrollNotification>(
|
|
||||||
onNotification: (scrollNotification) {
|
|
||||||
if (scrollNotification.metrics.pixels ==
|
|
||||||
scrollNotification
|
|
||||||
.metrics.maxScrollExtent) {
|
|
||||||
context
|
|
||||||
.read<CategoriesChildrenCubit>()
|
|
||||||
.getAllChildCategories(selectedId.value!);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
child: ConstrainedBox(
|
|
||||||
constraints: BoxConstraints(
|
|
||||||
maxHeight: 300), // Adjust height as needed
|
|
||||||
child: ListView.builder(
|
|
||||||
shrinkWrap: true,
|
|
||||||
itemCount: state.categories.length +
|
|
||||||
(state.isLoading ? 1 : 0),
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
if (index >= state.categories.length) {
|
|
||||||
return Center(
|
|
||||||
child: CircularProgressIndicator());
|
|
||||||
}
|
|
||||||
final category = state.categories[index];
|
|
||||||
return ListTile(
|
|
||||||
title: Text(category.name ?? ''),
|
|
||||||
onTap: () {
|
|
||||||
print('${category.name} clicked');
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -194,17 +95,14 @@ class _CategoriesMegaMenuState extends State<CategoriesMegaMenu> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _menuItem(String title) {
|
|
||||||
return ListTile(
|
|
||||||
title: Text(title),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return CompositedTransformTarget(
|
return CompositedTransformTarget(
|
||||||
link: _layerLink,
|
link: _layerLink,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
|
splashColor: Colors.transparent,
|
||||||
|
borderRadius: BorderRadius.zero,
|
||||||
|
hoverColor: Colors.transparent,
|
||||||
onTap: () {},
|
onTap: () {},
|
||||||
onHover: (value) {
|
onHover: (value) {
|
||||||
onHovered.value = value;
|
onHovered.value = value;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue