apskel-owner-flutter/lib/presentation/pages/outlet/outlet_information_page.dart
2025-08-20 13:52:49 +07:00

378 lines
12 KiB
Dart

import 'package:flutter/material.dart';
import 'package:auto_route/auto_route.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../application/outlet/current_outlet_loader/current_outlet_loader_bloc.dart';
import '../../../common/extension/extension.dart';
import '../../../common/theme/theme.dart';
import '../../../domain/outlet/outlet.dart';
import '../../../injection.dart';
import '../../components/appbar/appbar.dart';
import '../../components/spacer/spacer.dart';
// Outlet Information Page
@RoutePage()
class OutletInformationPage extends StatefulWidget implements AutoRouteWrapper {
const OutletInformationPage({super.key});
@override
State<OutletInformationPage> createState() => _OutletInformationPageState();
@override
Widget wrappedRoute(BuildContext context) => BlocProvider(
create: (_) =>
getIt<CurrentOutletLoaderBloc>()
..add(CurrentOutletLoaderEvent.fetched()),
child: this,
);
}
class _OutletInformationPageState extends State<OutletInformationPage>
with TickerProviderStateMixin {
late ScrollController _scrollController;
late AnimationController _fadeController;
late AnimationController _slideController;
late Animation<double> _fadeAnimation;
late Animation<Offset> _slideAnimation;
@override
void initState() {
super.initState();
_scrollController = ScrollController();
_fadeController = AnimationController(
duration: const Duration(milliseconds: 800),
vsync: this,
);
_slideController = AnimationController(
duration: const Duration(milliseconds: 600),
vsync: this,
);
_fadeAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
CurvedAnimation(parent: _fadeController, curve: Curves.easeInOut),
);
_slideAnimation =
Tween<Offset>(begin: const Offset(0, 0.3), end: Offset.zero).animate(
CurvedAnimation(parent: _slideController, curve: Curves.easeOutBack),
);
// Start animations
_fadeController.forward();
_slideController.forward();
}
@override
void dispose() {
_scrollController.dispose();
_fadeController.dispose();
_slideController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColor.background,
body: CustomScrollView(
controller: _scrollController,
slivers: [
SliverAppBar(
expandedHeight: 120.0,
floating: false,
pinned: true,
flexibleSpace: CustomAppBar(title: context.lang.outlet_information),
),
SliverToBoxAdapter(
child: FadeTransition(
opacity: _fadeAnimation,
child: SlideTransition(
position: _slideAnimation,
child: _buildContent(context),
),
),
),
],
),
);
}
Widget _buildContent(BuildContext context) {
return BlocBuilder<CurrentOutletLoaderBloc, CurrentOutletLoaderState>(
builder: (context, state) {
return Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildHeaderCard(state.outlet),
const SizedBox(height: 20),
_buildInfoSection(context, state.outlet),
const SizedBox(height: 20),
_buildBusinessSection(context, state.outlet),
const SizedBox(height: 20),
_buildStatusSection(context, state.outlet),
],
),
);
},
);
}
Widget _buildHeaderCard(Outlet outlet) {
return TweenAnimationBuilder<double>(
duration: const Duration(milliseconds: 800),
tween: Tween(begin: 0.0, end: 1.0),
builder: (context, value, child) {
return Transform.scale(
scale: 0.8 + (0.2 * value),
child: Container(
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: AppColor.primaryGradient,
),
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: AppColor.primary.withOpacity(0.3),
blurRadius: 20,
offset: const Offset(0, 10),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: AppColor.white.withOpacity(0.2),
borderRadius: BorderRadius.circular(12),
),
child: Icon(Icons.store, color: AppColor.white, size: 24),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
outlet.name,
style: AppStyle.h5.copyWith(
color: AppColor.white,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 4),
Text(
outlet.businessType,
style: AppStyle.md.copyWith(
color: AppColor.white.withOpacity(0.9),
),
),
],
),
),
],
),
],
),
),
);
},
);
}
Widget _buildInfoSection(BuildContext context, Outlet outlet) {
return _buildAnimatedCard(
delay: 200,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildSectionTitle(
context.lang.outlet_information,
Icons.info_outline,
),
SpaceHeight(20),
_buildInfoRow(
context.lang.address,
outlet.address,
Icons.location_on,
),
_buildInfoRow(
context.lang.phone_number,
outlet.phoneNumber,
Icons.phone,
),
],
),
);
}
Widget _buildBusinessSection(BuildContext context, Outlet outlet) {
return _buildAnimatedCard(
delay: 600,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildSectionTitle(
context.lang.business_settings,
Icons.settings_applications,
),
const SizedBox(height: 16),
_buildInfoRow(
context.lang.currency,
outlet.currency,
Icons.monetization_on,
),
_buildInfoRow(
context.lang.tax_rate,
'${outlet.taxRate}%',
Icons.percent,
),
],
),
);
}
Widget _buildStatusSection(BuildContext context, Outlet outlet) {
return _buildAnimatedCard(
delay: 800,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildSectionTitle(context.lang.status_text, Icons.toggle_on),
const SizedBox(height: 16),
Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
decoration: BoxDecoration(
color: outlet.isActive
? AppColor.success.withOpacity(0.1)
: AppColor.error.withOpacity(0.1),
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: outlet.isActive
? AppColor.success.withOpacity(0.3)
: AppColor.error.withOpacity(0.3),
),
),
child: Row(
children: [
Container(
width: 8,
height: 8,
decoration: BoxDecoration(
color: outlet.isActive ? AppColor.success : AppColor.error,
shape: BoxShape.circle,
),
),
const SizedBox(width: 12),
Text(
outlet.isActive ? context.lang.active : context.lang.inactive,
style: AppStyle.md.copyWith(
color: outlet.isActive ? AppColor.success : AppColor.error,
fontWeight: FontWeight.w600,
),
),
],
),
),
],
),
);
}
Widget _buildAnimatedCard({required Widget child, required int delay}) {
return TweenAnimationBuilder<double>(
duration: Duration(milliseconds: 600 + delay),
tween: Tween(begin: 0.0, end: 1.0),
builder: (context, value, _) {
return Transform.translate(
offset: Offset(0, 30 * (1 - value)),
child: Opacity(
opacity: value,
child: Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: AppColor.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: AppColor.black.withOpacity(0.05),
blurRadius: 10,
offset: const Offset(0, 5),
),
],
),
child: child,
),
),
);
},
);
}
Widget _buildSectionTitle(String title, IconData icon) {
return Row(
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: AppColor.primary.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
),
child: Icon(icon, color: AppColor.primary, size: 20),
),
const SizedBox(width: 12),
Text(
title,
style: AppStyle.lg.copyWith(
fontWeight: FontWeight.bold,
color: AppColor.textPrimary,
),
),
],
);
}
Widget _buildInfoRow(String label, String value, IconData icon) {
return Padding(
padding: const EdgeInsets.only(bottom: 16),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(icon, color: AppColor.textSecondary, size: 20),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: AppStyle.sm.copyWith(
color: AppColor.textSecondary,
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 4),
Text(
value,
style: AppStyle.md.copyWith(
color: AppColor.textPrimary,
fontWeight: FontWeight.w600,
),
),
],
),
),
],
),
);
}
}