263 lines
9.6 KiB
Dart
263 lines
9.6 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:flutter_riverpod/legacy.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:taxglide/consts/app_asstes.dart';
|
|
import 'package:taxglide/view/screens/notification_screen.dart';
|
|
import 'package:taxglide/controller/api_contoller.dart';
|
|
|
|
final serviceSearchProvider = StateProvider<String>((ref) => "");
|
|
|
|
class HomePageHeader extends ConsumerWidget {
|
|
final String userName;
|
|
|
|
const HomePageHeader({super.key, required this.userName});
|
|
|
|
@override
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
final screenWidth = MediaQuery.of(context).size.width;
|
|
final screenHeight = MediaQuery.of(context).size.height;
|
|
|
|
final headerHeight = screenHeight * 0.21;
|
|
final profileSize = screenWidth * 0.14;
|
|
final iconSize = screenWidth * 0.07;
|
|
final horizontalPadding = screenWidth * 0.04;
|
|
final searchBoxHeight = screenHeight * 0.07;
|
|
|
|
final welcomeFontSize = screenWidth * 0.035;
|
|
final userFontSize = screenWidth * 0.045;
|
|
final initialFontSize = screenWidth * 0.045;
|
|
|
|
// 🔴 Fetch Notification Count
|
|
final notifCountAsync = ref.watch(notificationCountProvider);
|
|
// 🔴 Fetch Profile Data for Image
|
|
final profileAsync = ref.watch(profileProvider);
|
|
|
|
return Stack(
|
|
clipBehavior: Clip.none,
|
|
children: [
|
|
// Background Header
|
|
ClipRRect(
|
|
borderRadius: const BorderRadius.only(
|
|
bottomLeft: Radius.circular(20),
|
|
bottomRight: Radius.circular(20),
|
|
),
|
|
child: Image.asset(
|
|
AppAssets.homepageheader,
|
|
width: double.infinity,
|
|
height: headerHeight,
|
|
fit: BoxFit.cover,
|
|
),
|
|
),
|
|
|
|
// Profile + Welcome + Notification Icon
|
|
Positioned(
|
|
top: headerHeight * 0.15,
|
|
left: horizontalPadding,
|
|
right: horizontalPadding,
|
|
child: Row(
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
children: [
|
|
// Profile Avatar
|
|
profileAsync.when(
|
|
data: (profileModel) {
|
|
final String? logoUrl = profileModel.data?.logo;
|
|
if (logoUrl != null && logoUrl.isNotEmpty) {
|
|
return Container(
|
|
width: profileSize,
|
|
height: profileSize,
|
|
decoration: BoxDecoration(
|
|
shape: BoxShape.circle,
|
|
border: Border.all(color: Colors.white, width: 2),
|
|
image: DecorationImage(
|
|
image: NetworkImage(logoUrl),
|
|
fit: BoxFit.cover,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
// Fallback to initial
|
|
return Container(
|
|
width: profileSize,
|
|
height: profileSize,
|
|
decoration: BoxDecoration(
|
|
shape: BoxShape.circle,
|
|
color: Colors.black.withOpacity(0.8),
|
|
border: Border.all(color: Colors.white, width: 2),
|
|
),
|
|
child: Center(
|
|
child: Text(
|
|
userName.isNotEmpty ? userName[0].toUpperCase() : "M",
|
|
style: TextStyle(
|
|
color: Colors.white,
|
|
fontSize: initialFontSize,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
),
|
|
);
|
|
},
|
|
loading: () => Container(
|
|
width: profileSize,
|
|
height: profileSize,
|
|
decoration: BoxDecoration(
|
|
shape: BoxShape.circle,
|
|
color: Colors.grey[300],
|
|
border: Border.all(color: Colors.white, width: 2),
|
|
),
|
|
),
|
|
error: (e, st) => Container(
|
|
width: profileSize,
|
|
height: profileSize,
|
|
decoration: BoxDecoration(
|
|
shape: BoxShape.circle,
|
|
color: Colors.black.withOpacity(0.8),
|
|
border: Border.all(color: Colors.white, width: 2),
|
|
),
|
|
child: Center(
|
|
child: Text(
|
|
userName.isNotEmpty ? userName[0].toUpperCase() : "M",
|
|
style: TextStyle(
|
|
color: Colors.white,
|
|
fontSize: initialFontSize,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
|
|
SizedBox(width: screenWidth * 0.03),
|
|
|
|
// Welcome & Username
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
"Welcome to TaxGlide",
|
|
style: TextStyle(
|
|
color: Colors.black,
|
|
fontSize: welcomeFontSize,
|
|
fontWeight: FontWeight.w400,
|
|
),
|
|
),
|
|
Text(
|
|
userName,
|
|
style: TextStyle(
|
|
color: Colors.black,
|
|
fontSize: userFontSize,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
overflow: TextOverflow.ellipsis,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
|
|
// Notifications with Badge
|
|
GestureDetector(
|
|
onTap: () => Get.to(NotificationScreen()),
|
|
child: Stack(
|
|
clipBehavior: Clip.none,
|
|
children: [
|
|
Container(
|
|
decoration: const BoxDecoration(
|
|
shape: BoxShape.circle,
|
|
color: Colors.black,
|
|
),
|
|
padding: EdgeInsets.all(screenWidth * 0.025),
|
|
child: Icon(
|
|
Icons.notifications,
|
|
color: Colors.white,
|
|
size: iconSize,
|
|
),
|
|
),
|
|
|
|
// 🔴 Notification Badge
|
|
Positioned(
|
|
right: -2,
|
|
top: -2,
|
|
child: notifCountAsync.when(
|
|
loading: () => const SizedBox.shrink(),
|
|
error: (e, st) => const SizedBox.shrink(),
|
|
data: (count) {
|
|
if (count.count == 0) {
|
|
return const SizedBox.shrink();
|
|
}
|
|
return Container(
|
|
padding: const EdgeInsets.all(4),
|
|
decoration: const BoxDecoration(
|
|
color: Colors.red,
|
|
shape: BoxShape.circle,
|
|
),
|
|
child: Text(
|
|
count.count.toString(),
|
|
style: const TextStyle(
|
|
fontSize: 10,
|
|
color: Colors.white,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
|
|
// Search Bar
|
|
Positioned(
|
|
top: headerHeight - (searchBoxHeight * 0.6),
|
|
left: screenWidth * 0.05,
|
|
right: screenWidth * 0.05,
|
|
child: Container(
|
|
height: searchBoxHeight,
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.circular(50),
|
|
border: Border.all(color: const Color(0xFFE4E4E4), width: 1),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.black.withOpacity(0.15),
|
|
blurRadius: 6,
|
|
offset: const Offset(0, 2),
|
|
),
|
|
],
|
|
),
|
|
child: TextField(
|
|
textAlign: TextAlign.start, // ✅ Start (left) alignment
|
|
style: TextStyle(fontSize: screenWidth * 0.04),
|
|
onChanged: (value) {
|
|
ref.read(serviceSearchProvider.notifier).state = value;
|
|
},
|
|
decoration: InputDecoration(
|
|
hintText: "Search services...",
|
|
hintStyle: TextStyle(
|
|
color: Colors.grey,
|
|
fontSize: screenWidth * 0.04,
|
|
),
|
|
prefixIcon: Icon(
|
|
Icons.search,
|
|
color: Colors.black54,
|
|
size: screenWidth * 0.06,
|
|
),
|
|
border: InputBorder.none,
|
|
|
|
// ✅ Only vertical center
|
|
contentPadding: EdgeInsets.symmetric(
|
|
vertical: searchBoxHeight * 0.3,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|