feat: Refactor code structure and optimize performance across multiple modules

This commit is contained in:
Achintha Isuru
2025-11-17 23:29:28 -05:00
parent 831570f2e0
commit a64cbd9edf
1508 changed files with 105319 additions and 0 deletions

View File

@@ -0,0 +1,191 @@
import 'package:auto_route/auto_route.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:krow/core/application/routing/routes.gr.dart';
import 'package:krow/core/data/models/event/event_model.dart';
import 'package:krow/core/presentation/gen/assets.gen.dart';
import 'package:krow/core/presentation/styles/kw_text_styles.dart';
import 'package:krow/core/presentation/styles/theme.dart';
class CreateEventPopup extends StatefulWidget {
const CreateEventPopup({
super.key,
required this.child,
required this.controller,
required this.opacity,
});
final Widget child;
final ListenableOverlayPortalController controller;
final double opacity;
@override
State<CreateEventPopup> createState() => _CreateEventPopupState();
}
class _CreateEventPopupState extends State<CreateEventPopup> {
late final ListenableOverlayPortalController _controller;
@override
void initState() {
_controller = widget.controller;
_controller.addListener(() {
try {
if (context.mounted) {
setState(() {});
}
} catch (e) {
print(e);
}
});
super.initState();
}
@override
Widget build(BuildContext context) {
return OverlayPortal(
controller: _controller,
overlayChildBuilder: (context) {
return AnimatedOpacity(
duration: const Duration(milliseconds: 200),
opacity: widget.opacity,
child: AnimatedScale(
duration: const Duration(milliseconds: 200),
scale: 0.1 + 0.9 * widget.opacity,
alignment: const Alignment(0, 0.8),
child: GestureDetector(
onTap: () {
_controller.hide();
},
child: Align(
alignment: Alignment.bottomCenter,
child: Padding(
padding: const EdgeInsets.only(bottom: 125),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Column(
mainAxisSize: MainAxisSize.min,
children: [
// _buildItem('Create Recurrent Event', () {
// context.router.push(CreateEventFlowRoute(
// children: [
// CreateEventRoute(
// eventType: EventScheduleType.recurring)
// ]));
// }),
// const Gap(8),
_buildItem('Create Event', () {
context.router.push(CreateEventFlowRoute(
children: [
CreateEventRoute(
eventType: EventScheduleType.oneTime)
]));
}),
const Gap(6),
Assets.images.icons.navigation.menuArrow.svg(),
],
),
],
),
),
)),
),
);
},
child: widget.child,
);
}
Widget _buildItem(String title, VoidCallback onTap) {
return GestureDetector(
onTap: () {
onTap();
_controller.hide();
},
child: Container(
width: 215,
alignment: Alignment.center,
decoration: BoxDecoration(
color: AppColors.buttonPrimaryYellowDrop,
borderRadius: BorderRadius.circular(24),
),
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
child: Text(
title,
style: AppTextStyles.bodyMediumMed,
),
),
);
}
@override
void dispose() {
if (context.mounted) _controller.hide();
super.dispose();
}
}
class ListenableOverlayPortalController extends OverlayPortalController {
List<VoidCallback> listeners = [];
Future<void> Function()? onShow;
Future<void> Function()? onHide;
ListenableOverlayPortalController();
addOnShowListener(Future<void> Function() listener) {
onShow = listener;
}
addOnHideListener(Future<void> Function() listener) {
onHide = listener;
}
@override
void show() async {
super.show();
try {
for (var element in listeners) {
element();
}
} catch (e) {
if (kDebugMode) {
print(e);
}
}
if (onShow != null) {
await onShow!();
}
}
@override
void hide() async {
if (onHide != null) {
await onHide!();
}
try {
super.hide();
} catch (e) {
if (kDebugMode) {
print(e);
}
}
for (var element in listeners) {
try {
element();
} catch (e) {
if (kDebugMode) {
print(e);
}
}
}
}
void addListener(VoidCallback listener) {
listeners.add(listener);
}
}

View File

@@ -0,0 +1,246 @@
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:gap/gap.dart';
import 'package:krow/core/application/di/injectable.dart';
import 'package:krow/core/application/routing/routes.gr.dart';
import 'package:krow/core/presentation/gen/assets.gen.dart';
import 'package:krow/core/presentation/styles/kw_text_styles.dart';
import 'package:krow/core/presentation/styles/theme.dart';
import 'package:krow/core/presentation/widgets/ui_kit/kw_button.dart';
import 'package:krow/core/sevices/app_update_service.dart';
import 'package:krow/features/home/presentation/create_event_widget.dart';
import '../../notificatins/domain/bloc/notifications_bloc.dart';
BuildContext? _nestedContext;
BuildContext? homeContext;
@RoutePage()
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
final ListenableOverlayPortalController _controller =
ListenableOverlayPortalController();
final List<PageRouteInfo> _routes = const [
EventsFlowRoute(),
InvoiceFlowRoute(),
NotificationFlowRoute(),
ProfileFlowRoute(),
];
bool _shouldHideBottomNavBar(BuildContext nestedContext) {
final currentPath = context.router.currentPath;
return _allowBottomNavBarRoutes
.any((route) => currentPath == route.toString());
}
final List<String> _allowBottomNavBarRoutes = [
'/home/events/list',
'/home/invoice/list',
'/home/notifications/list',
'/home/profile/preview',
];
double opacity = 0.0;
getMediaQueryData(BuildContext context) {
if (!_shouldHideBottomNavBar(context)) {
return MediaQuery.of(context);
} else {
//76 - navigation height, 22 - bottom padding
var newBottomPadding = MediaQuery.of(context).padding.bottom + 76 + 22;
var newPadding =
MediaQuery.of(context).padding.copyWith(bottom: newBottomPadding);
return MediaQuery.of(context).copyWith(padding: newPadding);
}
}
@override
void initState() {
super.initState();
_controller.addListener(() {
setState(() {});
});
_controller.addOnHideListener(_hide);
_controller.addOnShowListener(_show);
WidgetsBinding.instance.addPostFrameCallback((call) {
getIt<AppUpdateService>().checkForUpdate(context);
});
}
@override
Widget build(BuildContext context) {
homeContext = context;
return BlocProvider(
create: (context) => NotificationsBloc()..add(NotificationsInitEvent()),
child: Scaffold(
body: AutoTabsRouter(
duration: const Duration(milliseconds: 250),
routes: _routes,
builder: (context, child) {
_nestedContext = context;
return Stack(
children: [
MediaQuery(
data: getMediaQueryData(context),
child: child,
),
_buildBarrier(),
if (_shouldHideBottomNavBar(context)) _bottomNavBar(context),
],
);
},
),
),
);
}
Widget _buildBarrier() {
return IgnorePointer(
ignoring: opacity == 0.0,
child: AnimatedOpacity(
duration: const Duration(milliseconds: 200),
opacity: opacity,
child: GestureDetector(
onTap: () {
_controller.hide();
},
child: const SizedBox(
height: double.maxFinite,
width: double.maxFinite,
child: DecoratedBox(
decoration: BoxDecoration(
color: Colors.black38,
),
),
),
),
),
);
}
Widget _bottomNavBar(context) {
final tabsRouter = AutoTabsRouter.of(context);
return Positioned(
bottom: 22,
left: 16,
right: 16,
child: SafeArea(
top: false,
child: Container(
height: 76,
padding: const EdgeInsets.symmetric(horizontal: 24),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(38),
color: AppColors.bgColorDark,
),
child: Row(
children: [
_navBarItem('Events', Assets.images.icons.navigation.confetti, 0,
tabsRouter),
_navBarItem('Invoice', Assets.images.icons.navigation.emptyWallet,
1, tabsRouter),
Gap(8),
_createEventButton(),
Gap(8),
_navBarItem('Alerts', Assets.images.icons.appBar.notification, 2,
tabsRouter),
_navBarItem('Profile', Assets.images.icons.navigation.profile, 3,
tabsRouter),
],
),
),
),
);
}
Widget _navBarItem(
String text,
SvgGenImage icon,
int index,
tabsRouter,
) {
var color = tabsRouter.activeIndex == index
? AppColors.grayWhite
: AppColors.tintDarkBlue;
return Expanded(
child: GestureDetector(
onTap: () {
if(index<0) return;
if (_controller.isShowing) {
_controller.hide();
}
tabsRouter.setActiveIndex(index);
},
child: Container(
color: Colors.transparent,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
icon.svg(
colorFilter: ColorFilter.mode(
color,
BlendMode.srcIn,
),
),
const Gap(8),
Text(
text,
style: (tabsRouter.activeIndex == index
? AppTextStyles.bodyTinyMed
: AppTextStyles.bodyTinyReg)
.copyWith(color: color),
),
],
),
),
),
);
}
_createEventButton() {
return CreateEventPopup(
opacity: opacity,
controller: _controller,
child: KwButton.accent(
onPressed: () {
if (_controller.isShowing) {
_controller.hide();
} else {
_controller.show();
}
},
fit: KwButtonFit.circular,
iconSize: 24,
leftIcon: Assets.images.icons.navigation.noteFavorite,
).copyWith(
originalIconsColors: true,
color: _controller.isShowing
? AppColors.buttonPrimaryYellowDrop
: null));
}
Future<void> _hide() async {
setState(() {
opacity = 0.0;
});
await Future.delayed(const Duration(milliseconds: 200), () {});
}
Future<void> _show() async {
WidgetsBinding.instance.addPostFrameCallback((call) {
setState(() {
opacity = 1.0;
});
});
}
}