baseproject

This commit is contained in:
Gaurav Kumar
2025-09-06 19:21:52 +05:30
commit 01be9df2ed
254 changed files with 28342 additions and 0 deletions

View File

@@ -0,0 +1,626 @@
import 'package:base_project/core/constants/ui_constants.dart';
import 'package:base_project/core/theme/color_scheme.dart';
import 'package:base_project/routes/route_names.dart';
import 'package:base_project/shared/widgets/app_bar/modern_app_bar.dart';
import 'package:base_project/shared/widgets/cards/dashboard_card.dart';
import 'package:base_project/shared/widgets/buttons/quick_action_button.dart';
import 'package:base_project/shared/widgets/navigation/modern_drawer.dart';
import 'package:base_project/utils/managers/user_manager.dart';
import 'package:provider/provider.dart';
import 'package:base_project/view_model/system_params/system_params_view_model.dart';
import 'package:flutter/material.dart';
import '../../Entity/angulardatatype/Basicp1/Basicp1View/Basicp1_entity_list_screen.dart';
import '../../Entity/angulardatatype/Basicp1/Basicp1_viewModel/Basicp1_view_model_screen.dart';
class HomeView extends StatefulWidget {
const HomeView({super.key});
@override
State<HomeView> createState() => _HomeViewState();
}
class _HomeViewState extends State<HomeView> with TickerProviderStateMixin {
// Animation Controllers
late AnimationController _pageAnimationController;
late AnimationController _cardsAnimationController;
late AnimationController _actionsAnimationController;
// Animations
late Animation<double> _pageFadeAnimation;
late Animation<Offset> _pageSlideAnimation;
late Animation<double> _cardsScaleAnimation;
late Animation<double> _actionsScaleAnimation;
// Dashboard stats (replace with real API data)
List<Map<String, dynamic>> _dashboardStats = [];
final List<Map<String, dynamic>> _quickActions = [
{
'label': 'Profile',
'icon': Icons.person,
'onTap': () {},
'backgroundColor': null, // Use theme default
},
{
'label': 'Settings',
'icon': Icons.settings,
'onTap': () {},
'backgroundColor': null,
},
{
'label': 'Security',
'icon': Icons.security,
'onTap': () {},
'backgroundColor': null,
},
{
'label': 'Reports',
'icon': Icons.analytics,
'onTap': () {},
'backgroundColor': null,
},
];
final List<DrawerItem> _drawerItems = [
DrawerItem(
icon: Icons.person,
title: 'Profile',
subtitle: 'Manage your account',
onTap: (context) {
Navigator.pushNamed(context, RouteNames.profileView);
},
),
DrawerItem(
icon: Icons.system_security_update,
title: 'System Parameters',
subtitle: 'Configure system settings',
onTap: (context) {
Navigator.pushNamed(context, RouteNames.systemParamsView);
},
),
DrawerItem(
icon: Icons.password,
title: 'Change Password',
subtitle: 'Update your password',
onTap: (context) {
Navigator.pushNamed(context, RouteNames.changePasswordView);
},
),
// NEW ITEMS
DrawerItem(
icon: Icons.data_object,
title: 'Basicp1 Management',
subtitle: 'Manage Basicp1 entities',
onTap: (context) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ChangeNotifierProvider(
create: (context) => Basicp1ViewModelScreen(),
child: const Basicp1EntityListScreen(),
),
),
);
},
),
];
@override
void initState() {
super.initState();
_initializeAnimations();
_startPageAnimation();
_loadDashboardData();
}
void _initializeAnimations() {
// Page Animation Controller
_pageAnimationController = AnimationController(
duration: UIConstants.durationSlow,
vsync: this,
);
// Cards Animation Controller
_cardsAnimationController = AnimationController(
duration: UIConstants.durationNormal,
vsync: this,
);
// Actions Animation Controller
_actionsAnimationController = AnimationController(
duration: UIConstants.durationNormal,
vsync: this,
);
// Page Animations
_pageFadeAnimation = Tween<double>(
begin: 0.0,
end: 1.0,
).animate(CurvedAnimation(
parent: _pageAnimationController,
curve: UIConstants.curveNormal,
));
_pageSlideAnimation = Tween<Offset>(
begin: const Offset(0, 0.3),
end: Offset.zero,
).animate(CurvedAnimation(
parent: _pageAnimationController,
curve: UIConstants.curveNormal,
));
// Cards Animations
_cardsScaleAnimation = Tween<double>(
begin: 0.8,
end: 1.0,
).animate(CurvedAnimation(
parent: _cardsAnimationController,
curve: UIConstants.curveElastic,
));
// Actions Animations
_actionsScaleAnimation = Tween<double>(
begin: 0.8,
end: 1.0,
).animate(CurvedAnimation(
parent: _actionsAnimationController,
curve: UIConstants.curveElastic,
));
}
void _startPageAnimation() async {
await Future.delayed(const Duration(milliseconds: 300));
_pageAnimationController.forward();
await Future.delayed(const Duration(milliseconds: 400));
_cardsAnimationController.forward();
await Future.delayed(const Duration(milliseconds: 300));
_actionsAnimationController.forward();
}
Future<void> _loadDashboardData() async {
// TODO: replace with actual API calls, e.g., via a DashboardViewModel
// Simulate network delay
await Future.delayed(const Duration(milliseconds: 400));
setState(() {
_dashboardStats = [
{
'title': 'Total Users',
'subtitle': 'Active accounts',
'numericValue': 1234,
'valueSuffix': '',
'icon': Icons.people,
'type': DashboardCardType.primary,
'onTap': () {},
},
{
'title': 'System Uptime',
'subtitle': 'All systems operational',
'numericValue': 99.9,
'valueSuffix': '%',
'icon': Icons.check_circle,
'type': DashboardCardType.success,
'onTap': () {},
},
{
'title': 'Security Alerts',
'subtitle': 'Last 24 hours',
'numericValue': 2,
'valueSuffix': '',
'icon': Icons.security,
'type': DashboardCardType.info,
'onTap': () {},
},
{
'title': 'Avg. Response Time',
'subtitle': 'System performance',
'numericValue': 2.3,
'valueSuffix': 's',
'icon': Icons.speed,
'type': DashboardCardType.secondary,
'onTap': () {},
},
];
});
}
@override
void dispose() {
_pageAnimationController.dispose();
_cardsAnimationController.dispose();
_actionsAnimationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final colorScheme = theme.colorScheme;
final size = MediaQuery.of(context).size;
final userName = UserManager().userName;
return Scaffold(
backgroundColor: colorScheme.background,
appBar: ModernAppBar(
title: 'Dashboard',
centerTitle: false,
showLogoInTitle: true,
logoImage: _getDashboardLogoImage(colorScheme),
userAvatar: null,
userAvatarImage: _getDashboardLogoImage(colorScheme),
userName: userName,
onProfilePressed: () {
Navigator.pushNamed(context, RouteNames.profileView);
},
),
drawer: ModernDrawer(
items: _drawerItems,
),
body: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
colorScheme.background,
colorScheme.surfaceVariant.withOpacity(0.1),
colorScheme.primaryContainer.withOpacity(0.05),
],
),
),
child: SafeArea(
child: SingleChildScrollView(
padding: UIConstants.getResponsivePadding(
context,
mobile: const EdgeInsets.all(UIConstants.spacing24),
tablet: const EdgeInsets.all(UIConstants.spacing32),
desktop: const EdgeInsets.all(UIConstants.spacing40),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Welcome Section
_buildWelcomeSection(theme, colorScheme, userName),
SizedBox(
height: UIConstants.getResponsiveSpacing(
context,
mobile: UIConstants.spacing32,
tablet: UIConstants.spacing40,
desktop: UIConstants.spacing48,
)),
// Dashboard Stats
_buildDashboardStats(theme, colorScheme),
SizedBox(
height: UIConstants.getResponsiveSpacing(
context,
mobile: UIConstants.spacing40,
tablet: UIConstants.spacing56,
desktop: UIConstants.spacing72,
)),
// Quick Actions
_buildQuickActions(theme, colorScheme),
SizedBox(
height: UIConstants.getResponsiveSpacing(
context,
mobile: UIConstants.spacing40,
tablet: UIConstants.spacing56,
desktop: UIConstants.spacing72,
)),
// Recent Activity Section
_buildRecentActivity(theme, colorScheme),
],
),
),
),
),
);
}
ImageProvider<Object>? _getDashboardLogoImage(ColorScheme cs) {
// Prefer dynamic logo from system parameters if present
try {
final sysVm = Provider.of<SystemParamsViewModel>(context, listen: true);
if (sysVm.profileImageBytes != null &&
sysVm.profileImageBytes!.isNotEmpty) {
return MemoryImage(sysVm.profileImageBytes!);
}
} catch (_) {
// Provider not available – fall through to default asset
}
// Default asset logo
return const AssetImage('assets/images/image_not_found.png');
}
Widget _buildWelcomeSection(
ThemeData theme, ColorScheme colorScheme, String? userName) {
return AnimatedBuilder(
animation: _pageAnimationController,
builder: (context, child) {
return FadeTransition(
opacity: _pageFadeAnimation,
child: SlideTransition(
position: _pageSlideAnimation,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Welcome back, ${userName ?? 'User'}! 👋',
style: theme.textTheme.headlineMedium?.copyWith(
color: colorScheme.onBackground,
fontWeight: FontWeight.w700,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: UIConstants.spacing8),
Text(
'Here\'s what\'s happening with your system today',
style: theme.textTheme.bodyLarge?.copyWith(
color: colorScheme.onSurfaceVariant,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
],
),
),
);
},
);
}
// Removed in-body logo: AppBar now displays the logo.
Widget _buildDashboardStats(ThemeData theme, ColorScheme colorScheme) {
return AnimatedBuilder(
animation: _cardsAnimationController,
builder: (context, child) {
return Transform.scale(
scale: _cardsScaleAnimation.value,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'System Overview',
style: theme.textTheme.titleLarge?.copyWith(
color: colorScheme.onBackground,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: UIConstants.spacing24),
// Responsive Grid
LayoutBuilder(
builder: (context, constraints) {
final crossAxisCount = UIConstants.isMobile(context)
? 2
: UIConstants.isTablet(context)
? 3
: 4;
// Use fixed mainAxisExtent per breakpoint to avoid overflow
final double mainAxisExtent = UIConstants.isMobile(context)
? 130
: (UIConstants.isTablet(context) ? 160 : 180);
return GridView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: crossAxisCount,
crossAxisSpacing: UIConstants.spacing16,
mainAxisSpacing: UIConstants.spacing16,
mainAxisExtent: mainAxisExtent,
),
itemCount: _dashboardStats.length,
itemBuilder: (context, index) {
final stat = _dashboardStats[index];
return DashboardCard(
title: stat['title'],
subtitle: stat['subtitle'],
value: stat['value'],
numericValue: stat['numericValue'],
valueSuffix: stat['valueSuffix'],
animationDuration: UIConstants.durationNormal,
icon: stat['icon'],
type: stat['type'],
onTap: stat['onTap'],
);
},
);
},
),
],
),
);
},
);
}
Widget _buildQuickActions(ThemeData theme, ColorScheme colorScheme) {
return AnimatedBuilder(
animation: _actionsAnimationController,
builder: (context, child) {
return Transform.scale(
scale: _actionsScaleAnimation.value,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Quick Actions',
style: theme.textTheme.titleLarge?.copyWith(
color: colorScheme.onBackground,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: UIConstants.spacing24),
// Responsive Grid
LayoutBuilder(
builder: (context, constraints) {
final crossAxisCount = UIConstants.isMobile(context)
? 2
: UIConstants.isTablet(context)
? 4
: 6;
return GridView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: crossAxisCount,
crossAxisSpacing: UIConstants.spacing16,
mainAxisSpacing: UIConstants.spacing16,
childAspectRatio: 1.0,
),
itemCount: _quickActions.length,
itemBuilder: (context, index) {
final action = _quickActions[index];
return QuickActionButton(
label: action['label'],
icon: action['icon'],
onTap: action['onTap'],
backgroundColor: action['backgroundColor'],
size: UIConstants.logoSizeMedium,
);
},
);
},
),
],
),
);
},
);
}
Widget _buildRecentActivity(ThemeData theme, ColorScheme colorScheme) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Recent Activity',
style: theme.textTheme.titleLarge?.copyWith(
color: colorScheme.onBackground,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: UIConstants.spacing24),
Container(
padding: UIConstants.cardPaddingMedium,
decoration: BoxDecoration(
color: colorScheme.surface,
borderRadius: BorderRadius.circular(UIConstants.radius16),
boxShadow: [
BoxShadow(
color: colorScheme.shadow.withOpacity(0.1),
blurRadius: 8,
offset: const Offset(0, 2),
),
],
),
child: Column(
children: [
_buildActivityItem(
theme,
colorScheme,
Icons.security,
'Security scan completed',
'System security check finished successfully',
'2 minutes ago',
AppColorScheme.success,
),
const Divider(height: UIConstants.spacing24),
_buildActivityItem(
theme,
colorScheme,
Icons.update,
'System updated',
'Latest security patches installed',
'1 hour ago',
AppColorScheme.info,
),
const Divider(height: UIConstants.spacing24),
_buildActivityItem(
theme,
colorScheme,
Icons.backup,
'Backup completed',
'Daily backup process finished',
'3 hours ago',
colorScheme.primary,
),
],
),
),
],
);
}
Widget _buildActivityItem(
ThemeData theme,
ColorScheme colorScheme,
IconData icon,
String title,
String subtitle,
String time,
Color iconColor,
) {
return Row(
children: [
Container(
padding: const EdgeInsets.all(UIConstants.spacing8),
decoration: BoxDecoration(
color: iconColor.withOpacity(0.1),
borderRadius: BorderRadius.circular(UIConstants.radius8),
),
child: Icon(
icon,
color: iconColor,
size: UIConstants.iconSizeMedium,
),
),
const SizedBox(width: UIConstants.spacing16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: theme.textTheme.titleMedium?.copyWith(
color: colorScheme.onSurface,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: UIConstants.spacing4),
Text(
subtitle,
style: theme.textTheme.bodyMedium?.copyWith(
color: colorScheme.onSurfaceVariant,
),
),
],
),
),
Text(
time,
style: theme.textTheme.bodySmall?.copyWith(
color: colorScheme.onSurfaceVariant,
),
),
],
);
}
}

View File

@@ -0,0 +1,263 @@
import 'package:base_project/core/constants/ui_constants.dart';
import 'package:base_project/core/providers/dynamic_theme_provider.dart';
import 'package:base_project/shared/widgets/app_bar/modern_app_bar.dart';
import 'package:base_project/shared/widgets/inputs/modern_text_field.dart';
import 'package:base_project/shared/widgets/buttons/modern_button.dart';
import 'package:base_project/view_model/profile/profile_view_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
class AccountUpdateView extends StatefulWidget {
const AccountUpdateView({super.key});
@override
State<AccountUpdateView> createState() => _AccountUpdateViewState();
}
class _AccountUpdateViewState extends State<AccountUpdateView>
with TickerProviderStateMixin {
final _formKey = GlobalKey<FormState>();
late TextEditingController _companyName;
late TextEditingController _workspace;
late TextEditingController _gstNumber;
late TextEditingController _mobile;
late TextEditingController _email; // read-only
late TextEditingController _pancard;
late TextEditingController _working;
bool _active = true;
late AnimationController _anim;
late Animation<double> _fade;
late Animation<Offset> _slide;
@override
void initState() {
super.initState();
_companyName = TextEditingController();
_workspace = TextEditingController();
_gstNumber = TextEditingController();
_mobile = TextEditingController();
_email = TextEditingController();
_pancard = TextEditingController();
_working = TextEditingController();
_anim =
AnimationController(duration: UIConstants.durationSlow, vsync: this);
_fade = CurvedAnimation(parent: _anim, curve: UIConstants.curveNormal);
_slide = Tween<Offset>(begin: const Offset(0, .2), end: Offset.zero)
.animate(
CurvedAnimation(parent: _anim, curve: UIConstants.curveNormal));
WidgetsBinding.instance.addPostFrameCallback((_) {
final vm = Provider.of<ProfileViewModel>(context, listen: false);
final acc = vm.sysAccount ?? {};
_companyName.text = (acc['companyName'] ?? '').toString();
_workspace.text = (acc['workspace'] ?? '').toString();
_gstNumber.text = (acc['gstNumber'] ?? '').toString();
_mobile.text = (acc['mobile'] ?? '').toString();
_email.text = (acc['email'] ?? '').toString();
_pancard.text = (acc['pancard'] ?? '').toString();
_working.text = (acc['working'] ?? '').toString();
_active = acc['active'] == true;
_anim.forward();
});
}
@override
void dispose() {
_companyName.dispose();
_workspace.dispose();
_gstNumber.dispose();
_mobile.dispose();
_email.dispose();
_pancard.dispose();
_working.dispose();
_anim.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Consumer<DynamicThemeProvider>(
builder: (context, theme, child) {
final colorScheme = theme.getCurrentColorScheme(
Theme.of(context).brightness == Brightness.dark,
);
return Scaffold(
appBar: ModernAppBar(
title: 'Account Update',
automaticallyImplyLeading: true,
leading: IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () => Navigator.pop(context),
),
showThemeToggle: false,
showUserProfile: false,
),
body: AnimatedBuilder(
animation: _anim,
builder: (context, _) {
return FadeTransition(
opacity: _fade,
child: SlideTransition(
position: _slide,
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
colorScheme.primary.withOpacity(0.1),
colorScheme.secondary.withOpacity(0.05),
colorScheme.surface,
],
stops: const [0.0, 0.3, 1.0],
),
),
child: SingleChildScrollView(
padding: UIConstants.getResponsivePadding(
context,
mobile: UIConstants.screenPaddingMedium,
tablet: UIConstants.screenPaddingLarge,
desktop: UIConstants.screenPaddingLarge,
),
child: _buildFormCard(colorScheme),
),
),
),
);
},
),
);
},
);
}
Widget _buildFormCard(ColorScheme colorScheme) {
return Consumer<ProfileViewModel>(
builder: (context, vm, _) {
return Form(
key: _formKey,
child: Container(
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.95),
borderRadius: BorderRadius.circular(UIConstants.radius24),
border: Border.all(
color: colorScheme.surface.withOpacity(0.2), width: 1),
boxShadow: [
BoxShadow(
color: colorScheme.primary.withOpacity(0.1),
blurRadius: 20,
offset: const Offset(0, 10),
spreadRadius: 5,
),
],
),
padding: UIConstants.cardPaddingLarge,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
ModernTextField(
label: 'Company Name',
hint: 'Enter company name',
controller: _companyName,
prefixIcon: const Icon(Icons.business),
validator: (v) =>
(v == null || v.isEmpty) ? 'Required' : null,
),
SizedBox(height: UIConstants.spacing20),
ModernTextField(
label: 'Workspace',
hint: 'Enter workspace',
controller: _workspace,
prefixIcon: const Icon(Icons.apartment_outlined),
validator: (v) =>
(v == null || v.isEmpty) ? 'Required' : null,
),
SizedBox(height: UIConstants.spacing20),
ModernTextField(
label: 'GST Number',
hint: 'Enter GST number',
controller: _gstNumber,
prefixIcon: const Icon(Icons.confirmation_number_outlined),
),
SizedBox(height: UIConstants.spacing20),
ModernTextField(
label: 'Mobile',
hint: 'Enter mobile number',
controller: _mobile,
keyboardType: TextInputType.phone,
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
prefixIcon: const Icon(Icons.phone_outlined),
),
SizedBox(height: UIConstants.spacing20),
AbsorbPointer(
child: ModernTextField(
label: 'Email (read-only)',
hint: 'Email',
controller: _email,
prefixIcon: const Icon(Icons.email_outlined),
),
),
SizedBox(height: UIConstants.spacing20),
ModernTextField(
label: 'PAN Card',
hint: 'Enter PAN',
controller: _pancard,
prefixIcon: const Icon(Icons.badge_outlined),
),
SizedBox(height: UIConstants.spacing20),
ModernTextField(
label: 'Working',
hint: 'Working status',
controller: _working,
prefixIcon: const Icon(Icons.work_outline),
),
SizedBox(height: UIConstants.spacing20),
Row(
children: [
Switch(
value: _active,
onChanged: (v) => setState(() => _active = v),
),
const SizedBox(width: 8),
const Text('Active')
],
),
SizedBox(
height: UIConstants.getResponsiveSpacing(
context,
mobile: UIConstants.spacing32,
tablet: UIConstants.spacing40,
desktop: UIConstants.spacing48,
)),
ModernButton(
text: 'Update Account',
type: ModernButtonType.primary,
size: ModernButtonSize.large,
isLoading: vm.isUpdating,
icon: const Icon(Icons.save_outlined),
onPressed: () {
if (!_formKey.currentState!.validate()) return;
vm.updateAccount(context, {
'companyName': _companyName.text.trim(),
'workspace': _workspace.text.trim(),
'gstNumber': _gstNumber.text.trim(),
'mobile': _mobile.text.trim(),
'email': _email.text.trim(),
'pancard': _pancard.text.trim(),
'working': _working.text.trim(),
'active': _active,
});
},
),
],
),
),
);
},
);
}
}

View File

@@ -0,0 +1,401 @@
import 'package:base_project/commans/widgets/custom_textform_field.dart';
import 'package:base_project/commans/widgets/custome_elevated_button.dart';
import 'package:base_project/resources/app_colors.dart';
import 'package:base_project/utils/managers/user_manager.dart';
import 'package:base_project/utils/validator/text_feild_validator.dart';
import 'package:base_project/view_model/profile/profile_view_model.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:base_project/core/providers/dynamic_theme_provider.dart';
import 'package:base_project/core/constants/ui_constants.dart';
import 'package:base_project/shared/widgets/app_bar/modern_app_bar.dart';
import 'package:base_project/shared/widgets/inputs/modern_text_field.dart';
import 'package:base_project/shared/widgets/buttons/modern_button.dart';
class ChangePassword extends StatefulWidget {
const ChangePassword({super.key});
@override
State<ChangePassword> createState() => _ChangePasswordState();
}
class _ChangePasswordState extends State<ChangePassword>
with TickerProviderStateMixin {
final ValueNotifier<bool> _obscureTextCurrentPass = ValueNotifier<bool>(true);
final ValueNotifier<bool> _obscureTextNewPass = ValueNotifier<bool>(true);
final ValueNotifier<bool> _obscureTextConfirmPass = ValueNotifier<bool>(true);
final TextEditingController _currentPassController = TextEditingController();
final TextEditingController _newPassController = TextEditingController();
final TextEditingController _confirmPassController = TextEditingController();
// Global key for the form
final _formKey = GlobalKey<FormState>();
late AnimationController _animationController;
late Animation<double> _fadeAnimation;
late Animation<Offset> _slideAnimation;
@override
void initState() {
super.initState();
_animationController = AnimationController(
duration: UIConstants.durationSlow,
vsync: this,
);
_fadeAnimation = Tween<double>(
begin: 0.0,
end: 1.0,
).animate(CurvedAnimation(
parent: _animationController,
curve: UIConstants.curveNormal,
));
_slideAnimation = Tween<Offset>(
begin: const Offset(0, 0.3),
end: Offset.zero,
).animate(CurvedAnimation(
parent: _animationController,
curve: UIConstants.curveNormal,
));
WidgetsBinding.instance.addPostFrameCallback((_) {
_animationController.forward();
});
}
@override
void dispose() {
_currentPassController.dispose();
_newPassController.dispose();
_confirmPassController.dispose();
_obscureTextCurrentPass.dispose();
_obscureTextNewPass.dispose();
_obscureTextConfirmPass.dispose();
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Consumer<DynamicThemeProvider>(
builder: (context, dynamicThemeProvider, child) {
final colorScheme = dynamicThemeProvider.getCurrentColorScheme(
Theme.of(context).brightness == Brightness.dark);
final textTheme = Theme.of(context).textTheme;
return Scaffold(
appBar: ModernAppBar(
title: 'Change Password',
automaticallyImplyLeading: true,
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () => Navigator.pop(context),
),
showThemeToggle: false,
showUserProfile: false,
),
body: AnimatedBuilder(
animation: _animationController,
builder: (context, child) {
return FadeTransition(
opacity: _fadeAnimation,
child: SlideTransition(
position: _slideAnimation,
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
colorScheme.primary.withOpacity(0.1),
colorScheme.secondary.withOpacity(0.05),
colorScheme.surface,
],
stops: const [0.0, 0.3, 1.0],
),
),
child: SingleChildScrollView(
padding: UIConstants.getResponsivePadding(
context,
mobile: UIConstants.screenPaddingMedium,
tablet: UIConstants.screenPaddingLarge,
desktop: UIConstants.screenPaddingLarge,
),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Security Header Section
_buildSecurityHeader(
context, colorScheme, textTheme),
SizedBox(
height: UIConstants.getResponsiveSpacing(
context,
mobile: UIConstants.spacing32,
tablet: UIConstants.spacing40,
desktop: UIConstants.spacing48,
)),
// Password Form Section
_buildPasswordForm(context, colorScheme, textTheme),
],
),
),
),
),
),
);
},
),
);
},
);
}
Widget _buildSecurityHeader(
BuildContext context, ColorScheme colorScheme, TextTheme textTheme) {
return Container(
padding: UIConstants.getResponsivePadding(
context,
mobile: UIConstants.cardPaddingLarge,
tablet: UIConstants.cardPaddingLarge,
desktop: UIConstants.cardPaddingLarge,
),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.95),
borderRadius: BorderRadius.circular(UIConstants.radius24),
border: Border.all(
color: colorScheme.surface.withOpacity(0.2),
width: 1,
),
boxShadow: [
BoxShadow(
color: colorScheme.primary.withOpacity(0.1),
blurRadius: 20,
offset: const Offset(0, 10),
spreadRadius: 5,
),
],
),
child: Column(
children: [
// Security Icon
Container(
padding: const EdgeInsets.all(UIConstants.spacing20),
decoration: BoxDecoration(
color: colorScheme.primary.withOpacity(0.1),
shape: BoxShape.circle,
),
child: Icon(
Icons.security,
size: UIConstants.getResponsiveValue(
context,
mobile: 40,
tablet: 48,
desktop: 56,
),
color: colorScheme.primary,
),
),
SizedBox(height: UIConstants.spacing24),
Text(
'Change Password',
style: textTheme.headlineSmall?.copyWith(
fontWeight: FontWeight.w700,
color: colorScheme.primary,
),
textAlign: TextAlign.center,
),
SizedBox(height: UIConstants.spacing12),
Text(
'Update your account security by changing your password. Make sure to use a strong password.',
style: textTheme.bodyMedium?.copyWith(
color: colorScheme.onSurfaceVariant,
),
textAlign: TextAlign.center,
),
],
),
);
}
Widget _buildPasswordForm(
BuildContext context, ColorScheme colorScheme, TextTheme textTheme) {
return Container(
padding: UIConstants.getResponsivePadding(
context,
mobile: UIConstants.cardPaddingLarge,
tablet: UIConstants.cardPaddingLarge,
desktop: UIConstants.cardPaddingLarge,
),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.95),
borderRadius: BorderRadius.circular(UIConstants.radius24),
border: Border.all(
color: colorScheme.surface.withOpacity(0.2),
width: 1,
),
boxShadow: [
BoxShadow(
color: colorScheme.primary.withOpacity(0.1),
blurRadius: 20,
offset: const Offset(0, 10),
spreadRadius: 5,
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Password Details',
style: textTheme.titleLarge?.copyWith(
fontWeight: FontWeight.w600,
color: colorScheme.primary,
),
),
SizedBox(height: UIConstants.spacing24),
// Current Password Field
ValueListenableBuilder(
valueListenable: _obscureTextCurrentPass,
builder: (context, value, child) {
return ModernTextField(
label: 'Current Password',
hint: 'Enter your current password',
controller: _currentPassController,
prefixIcon: Icon(Icons.lock_outline),
suffixIcon: IconButton(
icon: Icon(
_obscureTextCurrentPass.value
? Icons.visibility_off
: Icons.visibility,
),
onPressed: () {
_obscureTextCurrentPass.value =
!_obscureTextCurrentPass.value;
},
),
obscureText: _obscureTextCurrentPass.value,
validator: TextFieldValidator.validatePassword,
);
},
),
SizedBox(
height: UIConstants.getResponsiveSpacing(
context,
mobile: UIConstants.spacing20,
tablet: UIConstants.spacing24,
desktop: UIConstants.spacing24,
)),
// New Password Field
ValueListenableBuilder(
valueListenable: _obscureTextNewPass,
builder: (context, value, child) {
return ModernTextField(
label: 'New Password',
hint: 'Enter your new password',
controller: _newPassController,
prefixIcon: Icon(Icons.lock_outline),
suffixIcon: IconButton(
icon: Icon(
_obscureTextNewPass.value
? Icons.visibility_off
: Icons.visibility,
),
onPressed: () {
_obscureTextNewPass.value = !_obscureTextNewPass.value;
},
),
obscureText: _obscureTextNewPass.value,
validator: TextFieldValidator.validatePassword,
);
},
),
SizedBox(
height: UIConstants.getResponsiveSpacing(
context,
mobile: UIConstants.spacing20,
tablet: UIConstants.spacing24,
desktop: UIConstants.spacing24,
)),
// Confirm Password Field
ValueListenableBuilder(
valueListenable: _obscureTextConfirmPass,
builder: (context, value, child) {
return ModernTextField(
label: 'Confirm New Password',
hint: 'Confirm your new password',
controller: _confirmPassController,
prefixIcon: Icon(Icons.lock_outline),
suffixIcon: IconButton(
icon: Icon(
_obscureTextConfirmPass.value
? Icons.visibility_off
: Icons.visibility,
),
onPressed: () {
_obscureTextConfirmPass.value =
!_obscureTextConfirmPass.value;
},
),
obscureText: _obscureTextConfirmPass.value,
validator: (value) {
return TextFieldValidator.validateConfirmPassword(
value, _newPassController.text);
},
);
},
),
SizedBox(
height: UIConstants.getResponsiveSpacing(
context,
mobile: UIConstants.spacing32,
tablet: UIConstants.spacing40,
desktop: UIConstants.spacing48,
)),
// Change Password Button
Consumer<ProfileViewModel>(
builder: (context, provider, _) {
return ModernButton(
text: 'Change Password',
type: ModernButtonType.primary,
size: ModernButtonSize.large,
isLoading: provider.isUpdating,
icon: Icon(Icons.security),
onPressed: () {
if (_formKey.currentState!.validate()) {
final uId = UserManager().userId;
final data = {
"userId": uId,
"oldPassword": _currentPassController.text,
"newPassword": _newPassController.text,
"confirmPassword": _confirmPassController.text,
};
provider.changePassword(data);
}
},
);
},
),
],
),
);
}
}

View File

@@ -0,0 +1,419 @@
import 'package:base_project/commans/widgets/custom_textform_field.dart';
import 'package:base_project/commans/widgets/custome_elevated_button.dart';
import 'package:base_project/model/user/user_profile.dart';
import 'package:base_project/resources/app_colors.dart';
import 'package:base_project/view_model/profile/profile_view_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_svg/svg.dart';
import 'package:provider/provider.dart';
import 'package:base_project/core/providers/dynamic_theme_provider.dart';
import 'package:base_project/core/constants/ui_constants.dart';
import 'package:base_project/shared/widgets/app_bar/modern_app_bar.dart';
import 'package:base_project/shared/widgets/inputs/modern_text_field.dart';
import 'package:base_project/shared/widgets/buttons/modern_button.dart';
import '../../../utils/image_constant.dart';
class EditProfile extends StatefulWidget {
final UserProfile userProfile;
const EditProfile({super.key, required this.userProfile});
@override
State<EditProfile> createState() => _EditProfileState();
}
class _EditProfileState extends State<EditProfile>
with TickerProviderStateMixin {
late TextEditingController _emailController;
late TextEditingController _userNameController;
late TextEditingController _mobNoController;
late TextEditingController _fullNameController;
late AnimationController _animationController;
late Animation<double> _fadeAnimation;
late Animation<Offset> _slideAnimation;
@override
void initState() {
super.initState();
_emailController = TextEditingController(text: widget.userProfile.email);
_userNameController =
TextEditingController(text: widget.userProfile.username);
_mobNoController =
TextEditingController(text: widget.userProfile.mobNo.toString());
_fullNameController =
TextEditingController(text: widget.userProfile.fullName.toString());
_animationController = AnimationController(
duration: UIConstants.durationSlow,
vsync: this,
);
_fadeAnimation = Tween<double>(
begin: 0.0,
end: 1.0,
).animate(CurvedAnimation(
parent: _animationController,
curve: UIConstants.curveNormal,
));
_slideAnimation = Tween<Offset>(
begin: const Offset(0, 0.3),
end: Offset.zero,
).animate(CurvedAnimation(
parent: _animationController,
curve: UIConstants.curveNormal,
));
WidgetsBinding.instance.addPostFrameCallback((_) {
_animationController.forward();
});
}
@override
void dispose() {
_emailController.dispose();
_userNameController.dispose();
_mobNoController.dispose();
_fullNameController.dispose();
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Consumer<DynamicThemeProvider>(
builder: (context, dynamicThemeProvider, child) {
final colorScheme = dynamicThemeProvider.getCurrentColorScheme(
Theme.of(context).brightness == Brightness.dark);
final textTheme = Theme.of(context).textTheme;
return Scaffold(
appBar: ModernAppBar(
title: 'Edit Profile',
automaticallyImplyLeading: true,
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () => Navigator.pop(context),
),
showThemeToggle: false,
showUserProfile: false,
),
body: AnimatedBuilder(
animation: _animationController,
builder: (context, child) {
return FadeTransition(
opacity: _fadeAnimation,
child: SlideTransition(
position: _slideAnimation,
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
colorScheme.primary.withOpacity(0.1),
colorScheme.secondary.withOpacity(0.05),
colorScheme.surface,
],
stops: const [0.0, 0.3, 1.0],
),
),
child: SingleChildScrollView(
padding: UIConstants.getResponsivePadding(
context,
mobile: UIConstants.screenPaddingMedium,
tablet: UIConstants.screenPaddingLarge,
desktop: UIConstants.screenPaddingLarge,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Profile Photo Section
_buildProfilePhotoSection(context, colorScheme),
SizedBox(
height: UIConstants.getResponsiveSpacing(
context,
mobile: UIConstants.spacing32,
tablet: UIConstants.spacing40,
desktop: UIConstants.spacing48,
)),
// Form Section
_buildFormSection(context, colorScheme, textTheme),
],
),
),
),
),
);
},
),
);
},
);
}
Widget _buildProfilePhotoSection(
BuildContext context, ColorScheme colorScheme) {
return Container(
padding: UIConstants.getResponsivePadding(
context,
mobile: UIConstants.cardPaddingLarge,
tablet: UIConstants.cardPaddingLarge,
desktop: UIConstants.cardPaddingLarge,
),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.95),
borderRadius: BorderRadius.circular(UIConstants.radius24),
border: Border.all(
color: colorScheme.surface.withOpacity(0.2),
width: 1,
),
boxShadow: [
BoxShadow(
color: colorScheme.primary.withOpacity(0.1),
blurRadius: 20,
offset: const Offset(0, 10),
spreadRadius: 5,
),
],
),
child: Column(
children: [
Text(
'Profile Picture',
style: Theme.of(context).textTheme.titleLarge?.copyWith(
fontWeight: FontWeight.w600,
color: colorScheme.primary,
),
),
SizedBox(height: UIConstants.spacing24),
Consumer<ProfileViewModel>(
builder: (context, provider, _) {
return Center(
child: Stack(
alignment: Alignment.center,
children: [
Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: colorScheme.primary.withOpacity(0.3),
width: 3,
),
boxShadow: [
BoxShadow(
color: colorScheme.primary.withOpacity(0.2),
blurRadius: 20,
offset: const Offset(0, 10),
spreadRadius: 5,
),
],
),
child: CircleAvatar(
radius: UIConstants.getResponsiveValue(
context,
mobile: 60,
tablet: 70,
desktop: 80,
),
backgroundColor: colorScheme.primary.withOpacity(0.1),
backgroundImage: provider.profileImageBytes != null
? MemoryImage(provider.profileImageBytes!)
: null,
child: provider.profileImageBytes != null
? null
: Icon(
Icons.person,
size: UIConstants.getResponsiveValue(
context,
mobile: 50,
tablet: 60,
desktop: 70,
),
color: colorScheme.primary,
),
),
),
Positioned(
bottom: 0,
right: 0,
child: Container(
decoration: BoxDecoration(
color: colorScheme.primary,
shape: BoxShape.circle,
border: Border.all(
color: Colors.white,
width: 3,
),
boxShadow: [
BoxShadow(
color: colorScheme.primary.withOpacity(0.3),
blurRadius: 10,
offset: const Offset(0, 5),
spreadRadius: 2,
),
],
),
child: IconButton(
icon: const Icon(Icons.camera_alt),
color: Colors.white,
onPressed: () {
provider.pickImg(context);
},
),
),
),
],
),
);
},
),
],
),
);
}
Widget _buildFormSection(
BuildContext context, ColorScheme colorScheme, TextTheme textTheme) {
return Container(
padding: UIConstants.getResponsivePadding(
context,
mobile: UIConstants.cardPaddingLarge,
tablet: UIConstants.cardPaddingLarge,
desktop: UIConstants.cardPaddingLarge,
),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.95),
borderRadius: BorderRadius.circular(UIConstants.radius24),
border: Border.all(
color: colorScheme.surface.withOpacity(0.2),
width: 1,
),
boxShadow: [
BoxShadow(
color: colorScheme.primary.withOpacity(0.1),
blurRadius: 20,
offset: const Offset(0, 10),
spreadRadius: 5,
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Personal Information',
style: textTheme.titleLarge?.copyWith(
fontWeight: FontWeight.w600,
color: colorScheme.primary,
),
),
SizedBox(height: UIConstants.spacing24),
// Full Name Field
ModernTextField(
label: 'Full Name',
hint: 'Enter your full name',
controller: _fullNameController,
prefixIcon: Icon(Icons.person_outline),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Full name is required';
}
return null;
},
),
SizedBox(
height: UIConstants.getResponsiveSpacing(
context,
mobile: UIConstants.spacing20,
tablet: UIConstants.spacing24,
desktop: UIConstants.spacing24,
)),
// Email Field
ModernTextField(
label: 'Email Address',
hint: 'Enter your email',
controller: _emailController,
prefixIcon: Icon(Icons.email_outlined),
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Email is required';
}
if (!RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$')
.hasMatch(value)) {
return 'Please enter a valid email';
}
return null;
},
),
SizedBox(
height: UIConstants.getResponsiveSpacing(
context,
mobile: UIConstants.spacing20,
tablet: UIConstants.spacing24,
desktop: UIConstants.spacing24,
)),
// Phone Field
ModernTextField(
label: 'Phone Number',
hint: 'Enter your phone number',
controller: _mobNoController,
prefixIcon: Icon(Icons.phone_outlined),
keyboardType: TextInputType.phone,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
LengthLimitingTextInputFormatter(10),
],
validator: (value) {
if (value == null || value.isEmpty) {
return 'Phone number is required';
}
if (value.length != 10) {
return 'Phone number must be 10 digits';
}
return null;
},
),
SizedBox(
height: UIConstants.getResponsiveSpacing(
context,
mobile: UIConstants.spacing32,
tablet: UIConstants.spacing40,
desktop: UIConstants.spacing48,
)),
// Save Button
Consumer<ProfileViewModel>(
builder: (context, provider, _) {
return ModernButton(
text: 'Save Changes',
type: ModernButtonType.primary,
size: ModernButtonSize.large,
isLoading: provider.isUpdating,
icon: Icon(Icons.save_outlined),
onPressed: () {
final data = {
'email': _emailController.text,
'fullName': _fullNameController.text,
'mob_no': _mobNoController.text,
};
provider.updateProfile(context, data);
},
);
},
),
],
),
);
}
}

View File

@@ -0,0 +1,573 @@
import 'package:base_project/data/response/status.dart';
import 'package:base_project/resources/app_colors.dart';
import 'package:base_project/routes/route_names.dart';
import 'package:base_project/utils/image_constant.dart';
import 'package:base_project/utils/managers/user_manager.dart';
import 'package:base_project/view/dashboard/profile/edit_profile.dart';
import 'package:base_project/view_model/profile/profile_view_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:provider/provider.dart';
import 'package:base_project/core/providers/dynamic_theme_provider.dart';
import 'package:base_project/core/constants/ui_constants.dart';
import 'package:base_project/shared/widgets/app_bar/modern_app_bar.dart';
import 'account_update.dart';
class ProfileView extends StatefulWidget {
const ProfileView({super.key});
@override
State<ProfileView> createState() => _ProfileViewState();
}
class _ProfileViewState extends State<ProfileView>
with TickerProviderStateMixin {
late final ProfileViewModel provider;
late AnimationController _animationController;
late Animation<double> _fadeAnimation;
late Animation<Offset> _slideAnimation;
@override
void initState() {
super.initState();
_animationController = AnimationController(
duration: UIConstants.durationSlow,
vsync: this,
);
_fadeAnimation = Tween<double>(
begin: 0.0,
end: 1.0,
).animate(CurvedAnimation(
parent: _animationController,
curve: UIConstants.curveNormal,
));
_slideAnimation = Tween<Offset>(
begin: const Offset(0, 0.3),
end: Offset.zero,
).animate(CurvedAnimation(
parent: _animationController,
curve: UIConstants.curveNormal,
));
WidgetsBinding.instance.addPostFrameCallback((_) {
provider = Provider.of<ProfileViewModel>(context, listen: false);
provider.getProfile();
provider.getProfileImg();
_animationController.forward();
});
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Consumer<DynamicThemeProvider>(
builder: (context, dynamicThemeProvider, child) {
final colorScheme = dynamicThemeProvider.getCurrentColorScheme(
Theme.of(context).brightness == Brightness.dark);
final textTheme = Theme.of(context).textTheme;
final size = MediaQuery.of(context).size;
return Scaffold(
appBar: ModernAppBar(
title: 'Profile',
automaticallyImplyLeading: true,
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () => Navigator.pop(context),
),
showThemeToggle: false,
showUserProfile: false,
),
body: AnimatedBuilder(
animation: _animationController,
builder: (context, child) {
return FadeTransition(
opacity: _fadeAnimation,
child: SlideTransition(
position: _slideAnimation,
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
colorScheme.primary.withOpacity(0.1),
colorScheme.secondary.withOpacity(0.05),
colorScheme.surface,
],
stops: const [0.0, 0.3, 1.0],
),
),
child: SingleChildScrollView(
padding: UIConstants.getResponsivePadding(
context,
mobile: UIConstants.screenPaddingMedium,
tablet: UIConstants.screenPaddingLarge,
desktop: UIConstants.screenPaddingLarge,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Profile Header Section
_buildProfileHeader(
context, colorScheme, textTheme, size),
SizedBox(
height: UIConstants.getResponsiveSpacing(
context,
mobile: UIConstants.spacing32,
tablet: UIConstants.spacing40,
desktop: UIConstants.spacing48,
)),
// Profile Actions Section
_buildProfileActions(context, colorScheme),
],
),
),
),
),
);
},
),
);
},
);
}
Widget _buildProfileHeader(BuildContext context, ColorScheme colorScheme,
TextTheme textTheme, Size size) {
return Consumer<ProfileViewModel>(
builder: (context, value, child) {
switch (provider.userProfile.status) {
case null:
case Status.LOADING:
return Container(
height: UIConstants.getResponsiveValue(
context,
mobile: 200.0,
tablet: 240.0,
desktop: 280.0,
),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.95),
borderRadius: BorderRadius.circular(UIConstants.radius24),
border: Border.all(
color: colorScheme.surface.withOpacity(0.2),
width: 1,
),
boxShadow: [
BoxShadow(
color: colorScheme.primary.withOpacity(0.1),
blurRadius: 20,
offset: const Offset(0, 10),
spreadRadius: 5,
),
],
),
child: const Center(
child: CircularProgressIndicator(),
),
);
case Status.SUCCESS:
return Container(
padding: UIConstants.getResponsivePadding(
context,
mobile: UIConstants.cardPaddingLarge,
tablet: UIConstants.cardPaddingLarge,
desktop: UIConstants.cardPaddingLarge,
),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.95),
borderRadius: BorderRadius.circular(UIConstants.radius24),
border: Border.all(
color: colorScheme.surface.withOpacity(0.2),
width: 1,
),
boxShadow: [
BoxShadow(
color: colorScheme.primary.withOpacity(0.1),
blurRadius: 20,
offset: const Offset(0, 10),
spreadRadius: 5,
),
],
),
child: Column(
children: [
// Profile Avatar with Enhanced Styling
Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: colorScheme.primary.withOpacity(0.3),
width: 3,
),
boxShadow: [
BoxShadow(
color: colorScheme.primary.withOpacity(0.2),
blurRadius: 20,
offset: const Offset(0, 10),
spreadRadius: 5,
),
],
),
child: CircleAvatar(
radius: UIConstants.getResponsiveValue(
context,
mobile: 50,
tablet: 60,
desktop: 70,
),
backgroundColor: colorScheme.primary.withOpacity(0.1),
backgroundImage: provider.profileImageBytes != null
? MemoryImage(provider.profileImageBytes!)
: null,
child: provider.profileImageBytes != null
? null
: Icon(
Icons.person,
size: UIConstants.getResponsiveValue(
context,
mobile: 40,
tablet: 50,
desktop: 60,
),
color: colorScheme.primary,
),
),
),
SizedBox(
height: UIConstants.getResponsiveSpacing(
context,
mobile: UIConstants.spacing24,
tablet: UIConstants.spacing32,
desktop: UIConstants.spacing40,
)),
// User Name
Text(
provider.userProfile.data?.fullName.toString() ?? "N/A",
style: textTheme.headlineSmall?.copyWith(
fontWeight: FontWeight.w700,
color: colorScheme.primary,
),
textAlign: TextAlign.center,
),
SizedBox(height: UIConstants.spacing8),
// Email
Container(
padding: const EdgeInsets.symmetric(
horizontal: UIConstants.spacing16,
vertical: UIConstants.spacing8,
),
decoration: BoxDecoration(
color: colorScheme.surfaceVariant.withOpacity(0.3),
borderRadius: BorderRadius.circular(UIConstants.radius12),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.email_outlined,
size: UIConstants.iconSizeSmall,
color: colorScheme.onSurfaceVariant,
),
const SizedBox(width: UIConstants.spacing8),
Text(
provider.userProfile.data?.email.toString() ?? "N/A",
style: textTheme.bodyMedium?.copyWith(
color: colorScheme.onSurfaceVariant,
),
),
],
),
),
SizedBox(height: UIConstants.spacing12),
// Phone Number
Container(
padding: const EdgeInsets.symmetric(
horizontal: UIConstants.spacing16,
vertical: UIConstants.spacing8,
),
decoration: BoxDecoration(
color: colorScheme.surfaceVariant.withOpacity(0.3),
borderRadius: BorderRadius.circular(UIConstants.radius12),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.phone_outlined,
size: UIConstants.iconSizeSmall,
color: colorScheme.onSurfaceVariant,
),
const SizedBox(width: UIConstants.spacing8),
Text(
provider.userProfile.data?.mobNo.toString() ?? "N/A",
style: textTheme.bodyMedium?.copyWith(
color: colorScheme.onSurfaceVariant,
),
),
],
),
),
],
),
);
case Status.ERROR:
return Container(
height: UIConstants.getResponsiveValue(
context,
mobile: 200,
tablet: 240,
desktop: 280,
),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.95),
borderRadius: BorderRadius.circular(UIConstants.radius24),
border: Border.all(
color: colorScheme.error.withOpacity(0.3),
width: 1,
),
),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.error_outline,
size: UIConstants.iconSizeXLarge,
color: colorScheme.error,
),
const SizedBox(height: UIConstants.spacing16),
Text(
'Failed to load profile',
style: textTheme.bodyLarge?.copyWith(
color: colorScheme.error,
),
),
],
),
),
);
}
},
);
}
Widget _buildProfileActions(BuildContext context, ColorScheme colorScheme) {
return Container(
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.95),
borderRadius: BorderRadius.circular(UIConstants.radius24),
border: Border.all(
color: colorScheme.surface.withOpacity(0.2),
width: 1,
),
boxShadow: [
BoxShadow(
color: colorScheme.primary.withOpacity(0.1),
blurRadius: 20,
offset: const Offset(0, 10),
spreadRadius: 5,
),
],
),
child: Column(
children: [
_buildModernListTile(
context,
colorScheme: colorScheme,
icon: Icons.edit_outlined,
title: 'Edit Profile',
subtitle: 'Update your personal information',
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => EditProfile(
userProfile: provider.userProfile.data!,
),
),
);
},
),
_buildDivider(colorScheme),
_buildModernListTile(
context,
colorScheme: colorScheme,
icon: Icons.manage_accounts_outlined,
title: 'Account Update',
subtitle: 'Update company/workspace details',
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const AccountUpdateView(),
),
);
},
),
_buildDivider(colorScheme),
_buildModernListTile(
context,
colorScheme: colorScheme,
icon: Icons.lock_outline,
title: 'Change Password',
subtitle: 'Update your account security',
onTap: () {
Navigator.pushNamed(context, RouteNames.changePasswordView);
},
),
_buildDivider(colorScheme),
_buildModernListTile(
context,
colorScheme: colorScheme,
icon: Icons.logout,
title: 'Logout',
subtitle: 'Sign out of your account',
iconColor: colorScheme.error,
onTap: () => _showLogoutDialog(context, colorScheme),
),
],
),
);
}
Widget _buildModernListTile(
BuildContext context, {
required ColorScheme colorScheme,
required IconData icon,
required String title,
required String subtitle,
required VoidCallback onTap,
Color? iconColor,
}) {
return Material(
color: Colors.transparent,
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(UIConstants.radius16),
child: Padding(
padding: UIConstants.getResponsivePadding(
context,
mobile: const EdgeInsets.all(UIConstants.spacing20),
tablet: const EdgeInsets.all(UIConstants.spacing24),
desktop: const EdgeInsets.all(UIConstants.spacing24),
),
child: Row(
children: [
Container(
padding: const EdgeInsets.all(UIConstants.spacing12),
decoration: BoxDecoration(
color: (iconColor ?? colorScheme.primary).withOpacity(0.1),
borderRadius: BorderRadius.circular(UIConstants.radius12),
),
child: Icon(
icon,
color: iconColor ?? colorScheme.primary,
size: UIConstants.iconSizeMedium,
),
),
const SizedBox(width: UIConstants.spacing16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w600,
color: colorScheme.onSurface,
),
),
const SizedBox(height: UIConstants.spacing4),
Text(
subtitle,
style: Theme.of(context).textTheme.bodySmall?.copyWith(
color: colorScheme.onSurfaceVariant,
),
),
],
),
),
Icon(
Icons.arrow_forward_ios,
color: colorScheme.onSurfaceVariant,
size: UIConstants.iconSizeSmall,
),
],
),
),
),
);
}
Widget _buildDivider(ColorScheme colorScheme) {
return Container(
margin: const EdgeInsets.symmetric(horizontal: UIConstants.spacing20),
height: 1,
color: colorScheme.surfaceVariant.withOpacity(0.3),
);
}
void _showLogoutDialog(BuildContext context, ColorScheme colorScheme) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(UIConstants.radius20),
),
title: Row(
children: [
Icon(
Icons.logout,
color: colorScheme.error,
size: UIConstants.iconSizeMedium,
),
const SizedBox(width: UIConstants.spacing12),
const Text("Confirm Logout"),
],
),
content: const Text("Are you sure you want to log out?"),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: Text(
"Cancel",
style: TextStyle(color: colorScheme.onSurfaceVariant),
),
),
ElevatedButton(
onPressed: () async {
await UserManager().clearUser();
Navigator.of(context).pop();
Navigator.pushReplacementNamed(context, RouteNames.loginView);
},
style: ElevatedButton.styleFrom(
backgroundColor: colorScheme.error,
foregroundColor: colorScheme.onError,
),
child: const Text("Log Out"),
),
],
);
},
);
}
}