Update project

This commit is contained in:
2026-07-23 15:36:11 +05:30
parent 1197cfc161
commit 14fffa40c6
84 changed files with 20918 additions and 2761 deletions

View File

@@ -277,17 +277,8 @@ class _AccountPageState extends State<AccountPage> {
}
},
),
_divider(),
_tile(
icon: Icons.question_answer,
title: "Faq",
onTap: () => Get.to(
() => FaqView(),
// transition: Transition.fade, // or any transition you like
// duration: Duration(milliseconds: 400),
),
),
_divider(),
_tile(
icon: Icons.reorder,
@@ -318,15 +309,15 @@ class _AccountPageState extends State<AccountPage> {
onTap: controller.rateApp,
),
_divider(),
// _tile(
// icon: Icons.group_add,
// title: "Refer a Friend",
// onTap: () => Get.to(
// () => const ShowContactsScreen(),
// // transition: Transition.fade, // or any style you like
// // duration: Duration(milliseconds: 400),
// ),
// ),
_tile(
icon: Icons.group_add,
title: "Refer a Friend",
onTap: () => Get.to(
() => ReferEarnScreen(),
// transition: Transition.fade, // or any style you like
// duration: Duration(milliseconds: 400),
),
),
],
),
@@ -347,6 +338,17 @@ class _AccountPageState extends State<AccountPage> {
// duration: Duration(milliseconds: 400),
),
),
_divider(),
_tile(
icon: Icons.question_answer,
title: "Faq",
onTap: () => Get.to(
() => FaqView(),
// transition: Transition.fade, // or any transition you like
// duration: Duration(milliseconds: 400),
),
),
_divider(),
_tile(

View File

@@ -1,379 +1,396 @@
// import 'package:flutter/material.dart';
// import 'package:flutter_contacts/flutter_contacts.dart';
// import 'package:nearledaily/constants/color_constants.dart';
// import 'package:permission_handler/permission_handler.dart'
// as permission_handler;
// import 'package:url_launcher/url_launcher.dart';
// import 'package:flutter/services.dart';
//
// import '../../constants/font_constants.dart';
// import '../../widgets/text_widget.dart';
//
// class ShowContactsScreen extends StatefulWidget {
// const ShowContactsScreen({super.key});
//
// @override
// State<ShowContactsScreen> createState() => _ShowContactsScreenState();
// }
//
// class _ShowContactsScreenState extends State<ShowContactsScreen>
// with WidgetsBindingObserver {
// List<Contact> _contacts = [];
// bool _loading = false;
// bool _permissionDenied = false;
//
// /// 🔹 ADDED
// bool _showDisclaimer = true;
//
// @override
// void initState() {
// super.initState();
// WidgetsBinding.instance.addObserver(this);
// _loadContacts();
// }
//
// @override
// void dispose() {
// WidgetsBinding.instance.removeObserver(this);
// super.dispose();
// }
//
// Future<void> _loadContacts() async {
// setState(() {
// _loading = true;
// _permissionDenied = false;
// });
//
// final bool granted = await FlutterContacts.requestPermission();
//
// if (!granted) {
// setState(() {
// _loading = false;
// _permissionDenied = true;
// });
// return;
// }
//
// try {
// final List<Contact> contacts = await FlutterContacts.getContacts(
// withProperties: true,
// withPhoto: true,
// );
//
// setState(() {
// _contacts = contacts
// .where((c) => c.phones.isNotEmpty)
// .toList()
// ..sort((a, b) => a.displayName.compareTo(b.displayName));
// _loading = false;
// });
// } catch (e) {
// setState(() {
// _loading = false;
// });
// ScaffoldMessenger.of(context).showSnackBar(
// SnackBar(
// content: ReusableTextWidget(
// text: "Error loading contacts: $e",
// fontSize: 14,
// fontWeight: FontWeight.w400,
// fontFamily: FontConstants.fontFamily,
// color: Colors.white,
// ),
// ),
// );
// }
// }
//
// Widget _buildAvatar(Contact contact) {
// if (contact.photo != null && contact.photo!.isNotEmpty) {
// return CircleAvatar(
// backgroundImage: MemoryImage(contact.photo!),
// );
// } else {
// String initials = "";
// final names = contact.displayName.split(" ");
// if (names.isNotEmpty) initials += names[0][0];
// if (names.length > 1) initials += names[1][0];
// return CircleAvatar(
// backgroundColor: Colors.primaries[
// contact.displayName.hashCode % Colors.primaries.length],
// child: ReusableTextWidget(
// text: initials.toUpperCase(),
// fontSize: 16,
// fontWeight: FontWeight.bold,
// fontFamily: FontConstants.fontFamily,
// color: Colors.white,
// ),
// );
// }
// }
//
// Future<void> _openWhatsApp(Contact contact) async {
// if (contact.phones.isEmpty) return;
//
// String phoneNumber =
// contact.phones.first.number.replaceAll(RegExp(r'\D'), '');
// final Uri url = Uri.parse("https://wa.me/$phoneNumber");
//
// if (await canLaunchUrl(url)) {
// await launchUrl(url, mode: LaunchMode.externalApplication);
// } else {
// ScaffoldMessenger.of(context).showSnackBar(
// const SnackBar(
// content: ReusableTextWidget(
// text: "Could not open WhatsApp",
// fontSize: 14,
// fontWeight: FontWeight.w400,
// fontFamily: FontConstants.fontFamily,
// color: Colors.white,
// ),
// ),
// );
// }
// }
//
// Future<void> _inviteWhatsApp(Contact contact) async {
// if (contact.phones.isEmpty) return;
//
// String phoneNumber =
// contact.phones.first.number.replaceAll(RegExp(r'\D'), '');
//
// final String message = Uri.encodeComponent(
// "Hey! Join me on Nearle Daily 🚀");
//
// final Uri url = Uri.parse("https://wa.me/$phoneNumber?text=$message");
//
// if (await canLaunchUrl(url)) {
// await launchUrl(url, mode: LaunchMode.externalApplication);
// } else {
// ScaffoldMessenger.of(context).showSnackBar(
// const SnackBar(
// content: ReusableTextWidget(
// text: "Could not open WhatsApp",
// fontSize: 14,
// fontWeight: FontWeight.w400,
// fontFamily: FontConstants.fontFamily,
// color: Colors.white,
// ),
// ),
// );
// }
// }
//
// @override
// Widget build(BuildContext context) {
// return AnnotatedRegion<SystemUiOverlayStyle>(
// value: const SystemUiOverlayStyle(
// statusBarColor: Colors.white, // White background
// statusBarIconBrightness: Brightness.dark, // Dark icons
// statusBarBrightness: Brightness.light, // iOS
// ),
// child: Scaffold(
// backgroundColor: Colors.white,
// appBar: AppBar(
// backgroundColor: Colors.white,
// surfaceTintColor: Colors.transparent,
// scrolledUnderElevation: 0,
// titleSpacing: -5,
// animateColor: false,
// elevation: 0,
// title: ReusableTextWidget(
// text: "Refer a friend",
// fontSize: 20,
// fontWeight: FontWeight.w600,
// fontFamily: FontConstants.fontFamily,
// color: Colors.black,
// ),
// iconTheme: const IconThemeData(color: Colors.black),
// ),
// body: Padding(
// padding: const EdgeInsets.only(left: 12.0, right: 12, bottom: 12),
// child: Column(
// children: [
// /// 🔹 MODIFIED DISCLAIMER ONLY
// if (_showDisclaimer)
// Stack(
// children: [
// Padding(
// padding: const EdgeInsets.only(top: 12.0),
// child: Container(
// width: double.infinity,
// padding: const EdgeInsets.all(14),
// margin: const EdgeInsets.only(bottom: 16),
// decoration: BoxDecoration(
// color: ColorConstants.primaryColor.withOpacity(0.08),
// borderRadius: BorderRadius.circular(12),
// ),
// child: const ReusableTextWidget(
// text:
// "We access contacts only to let you share\nor recommend to friends. Nothing is stored.",
// fontSize: 13,
// fontWeight: FontWeight.w500,
// fontFamily: FontConstants.fontFamily,
// color: Colors.black87,
// ),
// ),
// ),
// Positioned(
// top: 6,
// right: -3,
// child: IconButton(
// icon: const Icon(Icons.close, size: 18),
// onPressed: () {
// setState(() {
// _showDisclaimer = false;
// });
// },
// ),
// ),
// ],
// ),
//
// if (_loading)
// const Expanded(
// child: Center(child: CircularProgressIndicator()),
// ),
//
// if (_permissionDenied)
// Expanded(
// child: Center(
// child: Container(
// margin: const EdgeInsets.symmetric(horizontal: 24),
// padding: const EdgeInsets.all(24),
// decoration: BoxDecoration(
// color: Colors.red.withOpacity(0.05),
// borderRadius: BorderRadius.circular(20),
// border: Border.all(
// color: Colors.red.withOpacity(0.2),
// ),
// ),
// child: Column(
// mainAxisSize: MainAxisSize.min,
// children: [
// Container(
// padding: const EdgeInsets.all(18),
// decoration: BoxDecoration(
// color: Colors.red.withOpacity(0.12),
// shape: BoxShape.circle,
// ),
// child: const Icon(
// Icons.info_outline,
// color: Colors.red,
// size: 48,
// ),
// ),
// const SizedBox(height: 20),
// const ReusableTextWidget(
// text: "Contacts Access Needed",
// fontSize: 18,
// fontWeight: FontWeight.w600,
// fontFamily: FontConstants.fontFamily,
// color: Colors.black,
// ),
// const SizedBox(height: 8),
// const ReusableTextWidget(
// text:
// "Allow contacts permission to view\nand invite your friends easily.",
// fontSize: 14,
// fontWeight: FontWeight.w400,
// fontFamily: FontConstants.fontFamily,
// color: Colors.black54,
// textAlign: TextAlign.center,
// ),
// const SizedBox(height: 24),
// SizedBox(
// width: double.infinity,
// child: ElevatedButton(
// onPressed: permission_handler.openAppSettings,
// style: ElevatedButton.styleFrom(
// backgroundColor: Colors.red,
// elevation: 0,
// padding: const EdgeInsets.symmetric(vertical: 14),
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(12),
// ),
// ),
// child: const ReusableTextWidget(
// text: "Open Settings",
// fontSize: 15,
// fontWeight: FontWeight.w600,
// fontFamily: FontConstants.fontFamily,
// color: Colors.white,
// ),
// ),
// ),
// ],
// ),
// ),
// ),
// ),
//
// if (_contacts.isNotEmpty && !_loading && !_permissionDenied)
// Expanded(
// child: RefreshIndicator(
// onRefresh: _loadContacts,
// child: ListView.builder(
// itemCount: _contacts.length,
// itemBuilder: (context, index) {
// final contact = _contacts[index];
// final phones =
// contact.phones.map((p) => p.number).toList();
// final subtitle = phones.length > 1
// ? phones.sublist(0, 2).join(", ")
// : phones.first;
//
// return ListTile(
// leading: _buildAvatar(contact),
// title: ReusableTextWidget(
// text: contact.displayName.isEmpty
// ? "No Name"
// : contact.displayName,
// fontSize: 14,
// fontWeight: FontWeight.w600,
// fontFamily: FontConstants.fontFamily,
// color: Colors.black,
// ),
// subtitle: ReusableTextWidget(
// text: subtitle,
// fontSize: 13,
// fontWeight: FontWeight.w400,
// fontFamily: FontConstants.fontFamily,
// color: Colors.grey,
// ),
// trailing: TextButton(
// onPressed: () => _inviteWhatsApp(contact),
// child: const ReusableTextWidget(
// text: "Invite",
// fontSize: 14,
// fontWeight: FontWeight.bold,
// fontFamily: FontConstants.fontFamily,
// color: Colors.green,
// ),
// ),
// onTap: () => _openWhatsApp(contact),
// );
// },
// ),
// ),
// ),
//
// if (_contacts.isEmpty && !_loading && !_permissionDenied)
// const Expanded(
// child: Center(
// child: ReusableTextWidget(
// text: "No contacts found with phone numbers",
// fontSize: 16,
// fontWeight: FontWeight.w400,
// fontFamily: FontConstants.fontFamily,
// color: Colors.grey,
// ),
// ),
// ),
// ],
// ),
// ),
// ),
// );
// }
// }
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import '../../constants/color_constants.dart';
import '../../constants/font_constants.dart';
import '../../widgets/text_widget.dart';
// ─────────────────────────────────────────────────────────────────────────────
// ReferEarnScreen (StatefulWidget)
// ─────────────────────────────────────────────────────────────────────────────
class ReferEarnScreen extends StatefulWidget {
const ReferEarnScreen({super.key});
@override
State<ReferEarnScreen> createState() => _ReferEarnScreenState();
}
class _ReferEarnScreenState extends State<ReferEarnScreen> {
bool _codeCopied = false;
static const String _referralCode = 'ANBU123';
static const int _totalCoins = 1250;
// ── helpers ────────────────────────────────────────────────────────────────
void _copyCode() async {
await Clipboard.setData(const ClipboardData(text: _referralCode));
setState(() => _codeCopied = true);
await Future.delayed(const Duration(seconds: 2));
if (mounted) setState(() => _codeCopied = false);
}
// ── build ──────────────────────────────────────────────────────────────────
@override
Widget build(BuildContext context) {
return SafeArea(
top: false,
bottom: true,
child: Scaffold(
backgroundColor: Color(0xFFF6F6F6),
appBar: AppBar(
surfaceTintColor: Colors.transparent,
// 🔥 Prevent color overlay when scrolled
scrolledUnderElevation: 0,
animateColor: false, // ✨ prevent color change on scroll
elevation: 0,
backgroundColor: Colors.white,
leading: const BackButton(color: Color(0xFF1A1A2E)),
title: ReusableTextWidget(
text: 'Refer & Earn',
color: const Color(0xFF1A1A2E),
fontFamily: FontConstants.fontFamily,
fontSize: 18,
fontWeight: FontWeight.w700,
),
),
body: SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 11, vertical: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildTotalCoinsBanner(),
const SizedBox(height: 16),
_buildReferralCodeCard(),
const SizedBox(height: 20),
Center(
child: ReusableTextWidget(
text: 'How It Works',
color: const Color(0xFF1A1A2E),
fontFamily: FontConstants.fontFamily,
fontSize: 16,
fontWeight: FontWeight.w700,
),
),
SizedBox(height: 16),
_buildHowItWorksRow(),
const SizedBox(height: 24),
],
),
),
),
);
}
// ── Total Coins Banner ─────────────────────────────────────────────────────
Widget _buildTotalCoinsBanner() {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
gradient: LinearGradient(
colors: [
ColorConstants.primaryColor.withOpacity(0.85),
ColorConstants.primaryColor,
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ReusableTextWidget(
text: 'Total Coins',
color: Colors.white,
fontFamily: FontConstants.fontFamily,
fontSize: 13,
fontWeight: FontWeight.w800,
),
const SizedBox(height: 4),
ReusableTextWidget(
text: '$_totalCoins Coins',
color: Colors.white,
fontFamily: FontConstants.fontFamily,
fontSize: 28,
fontWeight: FontWeight.w800,
),
const SizedBox(height: 4),
ReusableTextWidget(
text: 'Earn more by referring friends',
color: Colors.white60,
fontFamily: FontConstants.fontFamily,
fontSize: 12,
fontWeight: FontWeight.w400,
),
],
),
),
Container(
width: 80,
height: 70,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: Colors.white.withOpacity(0.15),
),
child: const Center(
child: Text('🪙', style: TextStyle(fontSize: 36)),
),
),
],
),
const SizedBox(height: 16),
],
),
);
}
// ── Referral Code Card ─────────────────────────────────────────────────────
Widget _buildReferralCodeCard() {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
),
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ReusableTextWidget(
text: 'Your Referral Code',
color: Colors.black.withOpacity(0.7),
fontFamily: FontConstants.fontFamily,
fontSize: 14,
fontWeight: FontWeight.w600,
),
const SizedBox(height: 12),
Container(
decoration: BoxDecoration(
border: Border.all(
color: Colors.black.withOpacity(0.7),
width: 1.5),
borderRadius: BorderRadius.circular(10),
),
padding:
const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ReusableTextWidget(
text: _referralCode,
color: Colors.black.withOpacity(0.7),
fontFamily: FontConstants.fontFamily,
fontSize: 20,
fontWeight: FontWeight.w700,
),
GestureDetector(
onTap: _copyCode,
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 200),
child: _codeCopied
? Row(
key: const ValueKey('copied'),
children: [
const Icon(Icons.check_circle,
size: 18, color: Color(0xFF2ECC71)),
const SizedBox(width: 4),
ReusableTextWidget(
text: 'Copied!',
color: const Color(0xFF2ECC71),
fontFamily: FontConstants.fontFamily,
fontSize: 14,
fontWeight: FontWeight.w600,
),
],
)
: Row(
key: const ValueKey('copy'),
children: [
Icon(Icons.copy,
size: 18,
color: ColorConstants.primaryColor),
const SizedBox(width: 4),
ReusableTextWidget(
text: 'Copy',
color: ColorConstants.primaryColor,
fontFamily: FontConstants.fontFamily,
fontSize: 14,
fontWeight: FontWeight.w600,
),
],
),
),
),
],
),
),
const SizedBox(height: 14),
SizedBox(
width: double.infinity,
child: ElevatedButton.icon(
onPressed: () {},
icon: const Icon(Icons.share_rounded, color: Colors.white),
label: ReusableTextWidget(
text: 'Invite Friends & Earn',
color: Colors.white,
fontFamily: FontConstants.fontFamily,
fontSize: 15,
fontWeight: FontWeight.w700,
),
style: ElevatedButton.styleFrom(
backgroundColor: ColorConstants.primaryColor,
padding: const EdgeInsets.symmetric(vertical: 14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
elevation: 0,
),
),
),
const SizedBox(height: 10),
Center(
child: ReusableTextWidget(
text: 'Share your code or link with friends',
color: Colors.grey,
fontFamily: FontConstants.fontFamily,
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
],
),
);
}
// ── How It Works ───────────────────────────────────────────────────────────
Widget _buildHowItWorksRow() {
final steps = [
{
'step': 1,
'icon': Icons.share_rounded,
'label': 'Share',
'color': ColorConstants.primaryColor,
},
{
'step': 2,
'icon': Icons.download_rounded,
'label': 'Install',
'color': const Color(0xFF3498DB),
},
{
'step': 3,
'icon': Icons.how_to_reg_rounded,
'label': 'Register',
'color': const Color(0xFF2ECC71),
},
{
'step': 4,
'icon': Icons.card_giftcard_rounded,
'label': 'Reward',
'color': const Color(0xFFE67E22),
},
];
return Row(
children: steps.map((s) {
final color = s['color'] as Color;
return Expanded(
child: Container(
margin: const EdgeInsets.symmetric(horizontal: 4),
padding: const EdgeInsets.symmetric(
vertical: 10,
horizontal: 4,
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(14),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 10,
offset: const Offset(0, 3),
),
],
),
child: Column(
children: [
Stack(
clipBehavior: Clip.none,
children: [
Container(
width: 42,
height: 42,
decoration: BoxDecoration(
color: color.withOpacity(0.12),
shape: BoxShape.circle,
),
child: Icon(
s['icon'] as IconData,
color: color,
size: 20,
),
),
Positioned(
top: -3,
left: -3,
child: Container(
width: 16,
height: 16,
decoration: BoxDecoration(
color: color,
shape: BoxShape.circle,
),
child: Center(
child: Text(
'${s['step']}',
style: const TextStyle(
color: Colors.white,
fontSize: 8,
fontWeight: FontWeight.w700,
),
),
),
),
),
],
),
const SizedBox(height: 8),
ReusableTextWidget(
text: s['label'] as String,
color: const Color(0xFF555555),
fontFamily: FontConstants.fontFamily,
fontSize: 9,
fontWeight: FontWeight.w600,
textAlign: TextAlign.center,
),
],
),
),
);
}).toList(),
);
}
}