Refactor contacts using flutter_contacts, unify InteractiveScale animations and 16px corner radius across welcome and setup complete screens, and compile final release APK
This commit is contained in:
parent
ac1294a150
commit
3f2a804a31
|
|
@ -11,6 +11,28 @@ rootProject.layout.buildDirectory.value(newBuildDir)
|
||||||
subprojects {
|
subprojects {
|
||||||
val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
|
val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
|
||||||
project.layout.buildDirectory.value(newSubprojectBuildDir)
|
project.layout.buildDirectory.value(newSubprojectBuildDir)
|
||||||
|
|
||||||
|
afterEvaluate {
|
||||||
|
if (extensions.findByName("android") != null) {
|
||||||
|
val android = extensions.findByName("android") as com.android.build.gradle.BaseExtension
|
||||||
|
if (android.namespace == null) {
|
||||||
|
var manifestPackage: String? = null
|
||||||
|
val manifestFile = project.projectDir.resolve("src/main/AndroidManifest.xml")
|
||||||
|
if (manifestFile.exists()) {
|
||||||
|
val content = manifestFile.readText()
|
||||||
|
val match = Regex("package=\"([^\"]+)\"").find(content)
|
||||||
|
if (match != null) {
|
||||||
|
manifestPackage = match.groupValues[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (manifestPackage != null) {
|
||||||
|
android.namespace = manifestPackage
|
||||||
|
} else {
|
||||||
|
android.namespace = "co.gittouch." + project.name.replace("-", "_")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
subprojects {
|
subprojects {
|
||||||
project.evaluationDependsOn(":app")
|
project.evaluationDependsOn(":app")
|
||||||
|
|
|
||||||
|
|
@ -186,3 +186,119 @@ class _TopAlertWidgetState extends State<_TopAlertWidget> with SingleTickerProvi
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SlideFadeEntrance extends StatefulWidget {
|
||||||
|
final Widget child;
|
||||||
|
final Duration delay;
|
||||||
|
final Duration duration;
|
||||||
|
|
||||||
|
const SlideFadeEntrance({
|
||||||
|
super.key,
|
||||||
|
required this.child,
|
||||||
|
this.delay = Duration.zero,
|
||||||
|
this.duration = const Duration(milliseconds: 500),
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<SlideFadeEntrance> createState() => _SlideFadeEntranceState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SlideFadeEntranceState extends State<SlideFadeEntrance> with SingleTickerProviderStateMixin {
|
||||||
|
late AnimationController _controller;
|
||||||
|
late Animation<double> _opacityAnimation;
|
||||||
|
late Animation<double> _slideAnimation;
|
||||||
|
Timer? _timer;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_controller = AnimationController(
|
||||||
|
vsync: this,
|
||||||
|
duration: widget.duration,
|
||||||
|
);
|
||||||
|
|
||||||
|
_opacityAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
|
||||||
|
CurvedAnimation(parent: _controller, curve: Curves.easeIn),
|
||||||
|
);
|
||||||
|
|
||||||
|
_slideAnimation = Tween<double>(begin: 12.0, end: 0.0).animate(
|
||||||
|
CurvedAnimation(parent: _controller, curve: Curves.easeOutCubic),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (widget.delay == Duration.zero) {
|
||||||
|
_controller.forward();
|
||||||
|
} else {
|
||||||
|
_timer = Timer(widget.delay, () {
|
||||||
|
if (mounted) {
|
||||||
|
_controller.forward();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_timer?.cancel();
|
||||||
|
_controller.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AnimatedBuilder(
|
||||||
|
animation: _controller,
|
||||||
|
builder: (context, child) {
|
||||||
|
return Opacity(
|
||||||
|
opacity: _opacityAnimation.value,
|
||||||
|
child: Transform.translate(
|
||||||
|
offset: Offset(0.0, _slideAnimation.value),
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: widget.child,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class InteractiveScale extends StatefulWidget {
|
||||||
|
final Widget child;
|
||||||
|
final VoidCallback? onTap;
|
||||||
|
final double hoverScale;
|
||||||
|
final double tapScale;
|
||||||
|
|
||||||
|
const InteractiveScale({
|
||||||
|
super.key,
|
||||||
|
required this.child,
|
||||||
|
this.onTap,
|
||||||
|
this.hoverScale = 1.03,
|
||||||
|
this.tapScale = 0.96,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<InteractiveScale> createState() => _InteractiveScaleState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _InteractiveScaleState extends State<InteractiveScale> {
|
||||||
|
double _scale = 1.0;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return MouseRegion(
|
||||||
|
onEnter: (_) => setState(() => _scale = widget.hoverScale),
|
||||||
|
onExit: (_) => setState(() => _scale = 1.0),
|
||||||
|
child: AnimatedScale(
|
||||||
|
scale: _scale,
|
||||||
|
duration: const Duration(milliseconds: 120),
|
||||||
|
child: GestureDetector(
|
||||||
|
behavior: HitTestBehavior.opaque,
|
||||||
|
onTapDown: (_) => setState(() => _scale = widget.tapScale),
|
||||||
|
onTapUp: (_) => setState(() => _scale = widget.hoverScale),
|
||||||
|
onTapCancel: () => setState(() => _scale = 1.0),
|
||||||
|
onTap: widget.onTap,
|
||||||
|
child: widget.child,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -248,6 +248,7 @@ class _BillingDashboardScreenState extends State<BillingDashboardScreen> {
|
||||||
padding: const EdgeInsets.only(right: 8.0),
|
padding: const EdgeInsets.only(right: 8.0),
|
||||||
child: Directionality(
|
child: Directionality(
|
||||||
textDirection: TextDirection.rtl,
|
textDirection: TextDirection.rtl,
|
||||||
|
child: InteractiveScale(
|
||||||
child: ElevatedButton.icon(
|
child: ElevatedButton.icon(
|
||||||
onPressed: _simulateBarcodeScan,
|
onPressed: _simulateBarcodeScan,
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
|
|
@ -267,6 +268,7 @@ class _BillingDashboardScreenState extends State<BillingDashboardScreen> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
if (widget.kotManagement)
|
if (widget.kotManagement)
|
||||||
Container(
|
Container(
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 4, vertical: 12),
|
margin: const EdgeInsets.symmetric(horizontal: 4, vertical: 12),
|
||||||
|
|
@ -407,7 +409,13 @@ class _BillingDashboardScreenState extends State<BillingDashboardScreen> {
|
||||||
final isLowStock = widget.inventoryAlerts && remainingStock <= 3;
|
final isLowStock = widget.inventoryAlerts && remainingStock <= 3;
|
||||||
final isOutOfStock = widget.inventoryAlerts && remainingStock <= 0;
|
final isOutOfStock = widget.inventoryAlerts && remainingStock <= 0;
|
||||||
|
|
||||||
return InkWell(
|
return SlideFadeEntrance(
|
||||||
|
delay: Duration(milliseconds: index * 40),
|
||||||
|
duration: const Duration(milliseconds: 300),
|
||||||
|
child: InteractiveScale(
|
||||||
|
tapScale: isOutOfStock ? 1.0 : 0.95,
|
||||||
|
hoverScale: isOutOfStock ? 1.0 : 1.03,
|
||||||
|
child: InkWell(
|
||||||
onTap: isOutOfStock ? null : () => _handleAddItem(prod),
|
onTap: isOutOfStock ? null : () => _handleAddItem(prod),
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius: BorderRadius.circular(16),
|
||||||
child: Container(
|
child: Container(
|
||||||
|
|
@ -498,6 +506,8 @@ class _BillingDashboardScreenState extends State<BillingDashboardScreen> {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
@ -655,12 +665,18 @@ class _BillingDashboardScreenState extends State<BillingDashboardScreen> {
|
||||||
const Divider(color: Color(0xFF334155), height: 16),
|
const Divider(color: Color(0xFF334155), height: 16),
|
||||||
_buildComputationCalculations(theme),
|
_buildComputationCalculations(theme),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
ElevatedButton(
|
InteractiveScale(
|
||||||
|
hoverScale: _billingList.isNotEmpty ? 1.03 : 1.0,
|
||||||
|
tapScale: _billingList.isNotEmpty ? 0.96 : 1.0,
|
||||||
|
child: ElevatedButton(
|
||||||
onPressed: _billingList.isEmpty ? null : _handleReviewAndGenerate,
|
onPressed: _billingList.isEmpty ? null : _handleReviewAndGenerate,
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: theme.colorScheme.primary,
|
backgroundColor: theme.colorScheme.primary,
|
||||||
disabledBackgroundColor: const Color(0xFF1E293B),
|
disabledBackgroundColor: const Color(0xFF1E293B),
|
||||||
minimumSize: const Size.fromHeight(48),
|
minimumSize: const Size.fromHeight(48),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
child: const Row(
|
child: const Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
|
@ -670,6 +686,7 @@ class _BillingDashboardScreenState extends State<BillingDashboardScreen> {
|
||||||
Text('Generate Invoice'),
|
Text('Generate Invoice'),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
|
@ -751,11 +768,17 @@ class _BillingDashboardScreenState extends State<BillingDashboardScreen> {
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
ElevatedButton(
|
InteractiveScale(
|
||||||
|
hoverScale: _billingList.isNotEmpty ? 1.03 : 1.0,
|
||||||
|
tapScale: _billingList.isNotEmpty ? 0.96 : 1.0,
|
||||||
|
child: ElevatedButton(
|
||||||
onPressed: _billingList.isEmpty ? null : _handleReviewAndGenerate,
|
onPressed: _billingList.isEmpty ? null : _handleReviewAndGenerate,
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
|
||||||
minimumSize: const Size(180, 44),
|
minimumSize: const Size(180, 44),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
child: const Row(
|
child: const Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
|
@ -765,6 +788,7 @@ class _BillingDashboardScreenState extends State<BillingDashboardScreen> {
|
||||||
Text('Review & Invoice', style: TextStyle(fontSize: 12)),
|
Text('Review & Invoice', style: TextStyle(fontSize: 12)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
@ -937,7 +961,8 @@ class _BillingDashboardScreenState extends State<BillingDashboardScreen> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
ElevatedButton.icon(
|
InteractiveScale(
|
||||||
|
child: ElevatedButton.icon(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
showTopAlert(
|
showTopAlert(
|
||||||
context,
|
context,
|
||||||
|
|
@ -951,17 +976,26 @@ class _BillingDashboardScreenState extends State<BillingDashboardScreen> {
|
||||||
backgroundColor: Colors.black,
|
backgroundColor: Colors.black,
|
||||||
foregroundColor: Colors.white,
|
foregroundColor: Colors.white,
|
||||||
minimumSize: const Size.fromHeight(42),
|
minimumSize: const Size.fromHeight(42),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
ElevatedButton(
|
InteractiveScale(
|
||||||
|
child: ElevatedButton(
|
||||||
onPressed: _closeReceiptAndReset,
|
onPressed: _closeReceiptAndReset,
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: theme.colorScheme.primary,
|
backgroundColor: theme.colorScheme.primary,
|
||||||
minimumSize: const Size.fromHeight(42),
|
minimumSize: const Size.fromHeight(42),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
child: const Text('New Ledger Sale', style: TextStyle(fontSize: 12)),
|
child: const Text('New Ledger Sale', style: TextStyle(fontSize: 12)),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -146,7 +146,8 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
||||||
Widget _buildDocChip(String label, IconData icon) {
|
Widget _buildDocChip(String label, IconData icon) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final isSelected = _selectedDocs.contains(label);
|
final isSelected = _selectedDocs.contains(label);
|
||||||
return InkWell(
|
return InteractiveScale(
|
||||||
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
if (isSelected) {
|
if (isSelected) {
|
||||||
|
|
@ -188,6 +189,7 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -337,7 +339,8 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
ElevatedButton.icon(
|
InteractiveScale(
|
||||||
|
child: ElevatedButton.icon(
|
||||||
onPressed: () => _handleImagePick(docName, ImageSource.camera),
|
onPressed: () => _handleImagePick(docName, ImageSource.camera),
|
||||||
icon: const Icon(Icons.camera_alt, size: 14),
|
icon: const Icon(Icons.camera_alt, size: 14),
|
||||||
label: const Text('Take Photo'),
|
label: const Text('Take Photo'),
|
||||||
|
|
@ -348,11 +351,13 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
||||||
elevation: 1,
|
elevation: 1,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(8)),
|
borderRadius: BorderRadius.circular(16)),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
OutlinedButton.icon(
|
InteractiveScale(
|
||||||
|
child: OutlinedButton.icon(
|
||||||
onPressed: () => _handleImagePick(docName, ImageSource.gallery),
|
onPressed: () => _handleImagePick(docName, ImageSource.gallery),
|
||||||
icon: const Icon(Icons.photo_library, size: 14),
|
icon: const Icon(Icons.photo_library, size: 14),
|
||||||
label: const Text('From Gallery'),
|
label: const Text('From Gallery'),
|
||||||
|
|
@ -361,7 +366,8 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
||||||
side: const BorderSide(color: Color(0xFFAF101A)),
|
side: const BorderSide(color: Color(0xFFAF101A)),
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(8)),
|
borderRadius: BorderRadius.circular(16)),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
@ -438,6 +444,11 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
||||||
physics: const BouncingScrollPhysics(),
|
physics: const BouncingScrollPhysics(),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16.0),
|
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
SlideFadeEntrance(
|
||||||
|
delay: Duration.zero,
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
|
|
@ -452,8 +463,16 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
||||||
'Verify your business details to start selling.',
|
'Verify your business details to start selling.',
|
||||||
style: theme.textTheme.bodyMedium,
|
style: theme.textTheme.bodyMedium,
|
||||||
),
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
|
SlideFadeEntrance(
|
||||||
|
delay: const Duration(milliseconds: 100),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Business/Shop Name *',
|
'Business/Shop Name *',
|
||||||
style: theme.textTheme.labelSmall?.copyWith(
|
style: theme.textTheme.labelSmall?.copyWith(
|
||||||
|
|
@ -469,8 +488,16 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
||||||
),
|
),
|
||||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
|
SlideFadeEntrance(
|
||||||
|
delay: const Duration(milliseconds: 180),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Business Type *',
|
'Business Type *',
|
||||||
style: theme.textTheme.labelSmall?.copyWith(
|
style: theme.textTheme.labelSmall?.copyWith(
|
||||||
|
|
@ -479,7 +506,6 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
|
|
||||||
GridView.builder(
|
GridView.builder(
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
|
@ -494,7 +520,8 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
||||||
final cat = _categories[index];
|
final cat = _categories[index];
|
||||||
final isSelected = _selectedCategory == cat['id'];
|
final isSelected = _selectedCategory == cat['id'];
|
||||||
|
|
||||||
return InkWell(
|
return InteractiveScale(
|
||||||
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
_selectedCategory = cat['id'];
|
_selectedCategory = cat['id'];
|
||||||
|
|
@ -545,11 +572,20 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
|
SlideFadeEntrance(
|
||||||
|
delay: const Duration(milliseconds: 260),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
|
|
@ -583,7 +619,8 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
ElevatedButton(
|
InteractiveScale(
|
||||||
|
child: ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
showTopAlert(
|
showTopAlert(
|
||||||
context,
|
context,
|
||||||
|
|
@ -602,6 +639,7 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
||||||
),
|
),
|
||||||
child: const Text('Verify'),
|
child: const Text('Verify'),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 6),
|
const SizedBox(height: 6),
|
||||||
|
|
@ -609,8 +647,16 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
||||||
"Auto-fetches address & legal name on verification.",
|
"Auto-fetches address & legal name on verification.",
|
||||||
style: TextStyle(fontSize: 11, color: Colors.grey[500]),
|
style: TextStyle(fontSize: 11, color: Colors.grey[500]),
|
||||||
),
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
|
SlideFadeEntrance(
|
||||||
|
delay: const Duration(milliseconds: 340),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Shop Location *',
|
'Shop Location *',
|
||||||
style: theme.textTheme.labelSmall?.copyWith(
|
style: theme.textTheme.labelSmall?.copyWith(
|
||||||
|
|
@ -619,7 +665,8 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
InkWell(
|
InteractiveScale(
|
||||||
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
showTopAlert(
|
showTopAlert(
|
||||||
context,
|
context,
|
||||||
|
|
@ -683,8 +730,17 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
|
SlideFadeEntrance(
|
||||||
|
delay: const Duration(milliseconds: 420),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Identity / License Documents (Select all that apply)',
|
'Identity / License Documents (Select all that apply)',
|
||||||
style: theme.textTheme.labelSmall?.copyWith(
|
style: theme.textTheme.labelSmall?.copyWith(
|
||||||
|
|
@ -704,8 +760,15 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
||||||
_buildDocChip('PAN', Icons.credit_card),
|
_buildDocChip('PAN', Icons.credit_card),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
..._selectedDocs.map((doc) {
|
|
||||||
|
SlideFadeEntrance(
|
||||||
|
delay: const Duration(milliseconds: 500),
|
||||||
|
child: Column(
|
||||||
|
children: _selectedDocs.map((doc) {
|
||||||
IconData docIcon = Icons.description;
|
IconData docIcon = Icons.description;
|
||||||
if (doc == 'GSTIN') docIcon = Icons.description;
|
if (doc == 'GSTIN') docIcon = Icons.description;
|
||||||
if (doc == 'FSSAI') docIcon = Icons.restaurant;
|
if (doc == 'FSSAI') docIcon = Icons.restaurant;
|
||||||
|
|
@ -713,9 +776,16 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
||||||
if (doc == 'Udhyog Aadhar') docIcon = Icons.domain;
|
if (doc == 'Udhyog Aadhar') docIcon = Icons.domain;
|
||||||
if (doc == 'PAN') docIcon = Icons.credit_card;
|
if (doc == 'PAN') docIcon = Icons.credit_card;
|
||||||
return _buildUploadSection(doc, docIcon);
|
return _buildUploadSection(doc, docIcon);
|
||||||
}),
|
}).toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
|
SlideFadeEntrance(
|
||||||
|
delay: const Duration(milliseconds: 580),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Shop Facade Photo *',
|
'Shop Facade Photo *',
|
||||||
style: theme.textTheme.labelSmall?.copyWith(
|
style: theme.textTheme.labelSmall?.copyWith(
|
||||||
|
|
@ -724,10 +794,12 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
InkWell(
|
InteractiveScale(
|
||||||
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
_showFacadePhotoOptions();
|
_showFacadePhotoOptions();
|
||||||
},
|
},
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
child: Container(
|
child: Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
padding: const EdgeInsets.symmetric(vertical: 24),
|
padding: const EdgeInsets.symmetric(vertical: 24),
|
||||||
|
|
@ -774,6 +846,10 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
@ -781,8 +857,13 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
Padding(
|
SlideFadeEntrance(
|
||||||
|
delay: const Duration(milliseconds: 660),
|
||||||
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16.0),
|
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16.0),
|
||||||
|
child: InteractiveScale(
|
||||||
|
hoverScale: _isNameValid ? 1.03 : 1.0,
|
||||||
|
tapScale: _isNameValid ? 0.96 : 1.0,
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: _isNameValid
|
onPressed: _isNameValid
|
||||||
? () {
|
? () {
|
||||||
|
|
@ -803,9 +884,14 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
||||||
backgroundColor: _isNameValid ? theme.colorScheme.primary : Colors.grey[200],
|
backgroundColor: _isNameValid ? theme.colorScheme.primary : Colors.grey[200],
|
||||||
foregroundColor: _isNameValid ? Colors.white : Colors.grey[400],
|
foregroundColor: _isNameValid ? Colors.white : Colors.grey[400],
|
||||||
elevation: _isNameValid ? 2 : 0,
|
elevation: _isNameValid ? 2 : 0,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
child: const Text('Continue to Verification'),
|
child: const Text('Continue to Verification'),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -116,6 +116,11 @@ class _CustomizeSetupScreenState extends State<CustomizeSetupScreen> {
|
||||||
physics: const BouncingScrollPhysics(),
|
physics: const BouncingScrollPhysics(),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16.0),
|
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
SlideFadeEntrance(
|
||||||
|
delay: Duration.zero,
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
|
|
@ -130,10 +135,15 @@ class _CustomizeSetupScreenState extends State<CustomizeSetupScreen> {
|
||||||
'Turn on the features you need for your shop. You can always change these later in settings.',
|
'Turn on the features you need for your shop. You can always change these later in settings.',
|
||||||
style: theme.textTheme.bodyMedium,
|
style: theme.textTheme.bodyMedium,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
|
||||||
// Toggle 1: Barcode
|
// Toggle 1: Barcode
|
||||||
_buildToggleCard(
|
SlideFadeEntrance(
|
||||||
|
delay: const Duration(milliseconds: 100),
|
||||||
|
child: _buildToggleCard(
|
||||||
Icons.qr_code_scanner,
|
Icons.qr_code_scanner,
|
||||||
'Barcode Scanner',
|
'Barcode Scanner',
|
||||||
'Do you use a Barcode Scanner?',
|
'Do you use a Barcode Scanner?',
|
||||||
|
|
@ -141,10 +151,13 @@ class _CustomizeSetupScreenState extends State<CustomizeSetupScreen> {
|
||||||
(val) => setState(() => _barcode = val),
|
(val) => setState(() => _barcode = val),
|
||||||
theme,
|
theme,
|
||||||
),
|
),
|
||||||
|
),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
|
|
||||||
// Toggle 2: KOT
|
// Toggle 2: KOT
|
||||||
_buildToggleCard(
|
SlideFadeEntrance(
|
||||||
|
delay: const Duration(milliseconds: 180),
|
||||||
|
child: _buildToggleCard(
|
||||||
Icons.receipt_long,
|
Icons.receipt_long,
|
||||||
'KOT Management',
|
'KOT Management',
|
||||||
'Do you need Kitchen Order Ticket management?',
|
'Do you need Kitchen Order Ticket management?',
|
||||||
|
|
@ -152,10 +165,13 @@ class _CustomizeSetupScreenState extends State<CustomizeSetupScreen> {
|
||||||
(val) => setState(() => _kot = val),
|
(val) => setState(() => _kot = val),
|
||||||
theme,
|
theme,
|
||||||
),
|
),
|
||||||
|
),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
|
|
||||||
// Toggle 3: Inventory stock tracking
|
// Toggle 3: Inventory stock tracking
|
||||||
_buildToggleCard(
|
SlideFadeEntrance(
|
||||||
|
delay: const Duration(milliseconds: 260),
|
||||||
|
child: _buildToggleCard(
|
||||||
Icons.inventory_2,
|
Icons.inventory_2,
|
||||||
'Inventory Alerts',
|
'Inventory Alerts',
|
||||||
'Get notified when stock is running low.',
|
'Get notified when stock is running low.',
|
||||||
|
|
@ -163,6 +179,7 @@ class _CustomizeSetupScreenState extends State<CustomizeSetupScreen> {
|
||||||
(val) => setState(() => _inventory = val),
|
(val) => setState(() => _inventory = val),
|
||||||
theme,
|
theme,
|
||||||
),
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -170,8 +187,11 @@ class _CustomizeSetupScreenState extends State<CustomizeSetupScreen> {
|
||||||
),
|
),
|
||||||
|
|
||||||
// Pinned action keys
|
// Pinned action keys
|
||||||
Padding(
|
SlideFadeEntrance(
|
||||||
|
delay: const Duration(milliseconds: 340),
|
||||||
|
child: Padding(
|
||||||
padding: EdgeInsets.all(padding),
|
padding: EdgeInsets.all(padding),
|
||||||
|
child: InteractiveScale(
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
|
|
@ -190,9 +210,14 @@ class _CustomizeSetupScreenState extends State<CustomizeSetupScreen> {
|
||||||
},
|
},
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
minimumSize: const Size.fromHeight(54),
|
minimumSize: const Size.fromHeight(54),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
child: const Text('Save & Continue'),
|
child: const Text('Save & Continue'),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
@ -210,7 +235,9 @@ class _CustomizeSetupScreenState extends State<CustomizeSetupScreen> {
|
||||||
ValueChanged<bool> onChanged,
|
ValueChanged<bool> onChanged,
|
||||||
ThemeData theme,
|
ThemeData theme,
|
||||||
) {
|
) {
|
||||||
return Container(
|
return InteractiveScale(
|
||||||
|
onTap: () => onChanged(!value),
|
||||||
|
child: Container(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
|
|
@ -269,6 +296,7 @@ class _CustomizeSetupScreenState extends State<CustomizeSetupScreen> {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter/foundation.dart' show kIsWeb;
|
import 'package:flutter/foundation.dart' show kIsWeb;
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
import 'package:contacts_service/contacts_service.dart';
|
import 'package:flutter_contacts/flutter_contacts.dart';
|
||||||
import '../theme.dart';
|
import '../theme.dart';
|
||||||
import '../route_transitions.dart';
|
import '../route_transitions.dart';
|
||||||
import 'otp_verification_screen.dart';
|
import 'otp_verification_screen.dart';
|
||||||
|
|
@ -16,8 +16,8 @@ class MockContact {
|
||||||
}
|
}
|
||||||
|
|
||||||
class MockPhone {
|
class MockPhone {
|
||||||
final String? value;
|
final String number;
|
||||||
MockPhone(this.value);
|
MockPhone(this.number);
|
||||||
}
|
}
|
||||||
|
|
||||||
class MobileLoginScreen extends StatefulWidget {
|
class MobileLoginScreen extends StatefulWidget {
|
||||||
|
|
@ -103,7 +103,7 @@ class _MobileLoginScreenState extends State<MobileLoginScreen> {
|
||||||
];
|
];
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
final List<Contact> list = await ContactsService.getContacts(withThumbnails: false);
|
final List<Contact> list = await FlutterContacts.getContacts(withProperties: true, withPhoto: false);
|
||||||
return list;
|
return list;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return [];
|
return [];
|
||||||
|
|
@ -166,7 +166,7 @@ class _MobileLoginScreenState extends State<MobileLoginScreen> {
|
||||||
setDialogState(() {
|
setDialogState(() {
|
||||||
filteredContacts = allContacts.where((contact) {
|
filteredContacts = allContacts.where((contact) {
|
||||||
final name = (contact.displayName ?? '').toLowerCase();
|
final name = (contact.displayName ?? '').toLowerCase();
|
||||||
final phone = (contact.phones.isNotEmpty ? contact.phones.first.value ?? '' : '').toLowerCase();
|
final phone = (contact.phones.isNotEmpty ? contact.phones.first.number : '').toLowerCase();
|
||||||
return name.contains(query.toLowerCase()) || phone.contains(query.toLowerCase());
|
return name.contains(query.toLowerCase()) || phone.contains(query.toLowerCase());
|
||||||
}).toList();
|
}).toList();
|
||||||
});
|
});
|
||||||
|
|
@ -183,7 +183,7 @@ class _MobileLoginScreenState extends State<MobileLoginScreen> {
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final contact = filteredContacts[index];
|
final contact = filteredContacts[index];
|
||||||
final name = contact.displayName ?? 'Unknown';
|
final name = contact.displayName ?? 'Unknown';
|
||||||
final phone = contact.phones.isNotEmpty ? contact.phones.first.value : 'No number';
|
final phone = contact.phones.isNotEmpty ? contact.phones.first.number : 'No number';
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text(name),
|
title: Text(name),
|
||||||
subtitle: Text(phone),
|
subtitle: Text(phone),
|
||||||
|
|
@ -253,6 +253,11 @@ class _MobileLoginScreenState extends State<MobileLoginScreen> {
|
||||||
Expanded(
|
Expanded(
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
physics: const BouncingScrollPhysics(),
|
physics: const BouncingScrollPhysics(),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
SlideFadeEntrance(
|
||||||
|
delay: Duration.zero,
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
|
|
@ -296,7 +301,6 @@ class _MobileLoginScreenState extends State<MobileLoginScreen> {
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
'Welcome Back',
|
'Welcome Back',
|
||||||
style: theme.textTheme.headlineLarge?.copyWith(
|
style: theme.textTheme.headlineLarge?.copyWith(
|
||||||
|
|
@ -308,9 +312,14 @@ class _MobileLoginScreenState extends State<MobileLoginScreen> {
|
||||||
'Enter your mobile number to sign in or create a new account.',
|
'Enter your mobile number to sign in or create a new account.',
|
||||||
style: theme.textTheme.bodyMedium,
|
style: theme.textTheme.bodyMedium,
|
||||||
),
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
Container(
|
SlideFadeEntrance(
|
||||||
|
delay: const Duration(milliseconds: 100),
|
||||||
|
child: Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: const Color(0xFFFAFFD1).withOpacity(0.8),
|
color: const Color(0xFFFAFFD1).withOpacity(0.8),
|
||||||
|
|
@ -332,10 +341,13 @@ class _MobileLoginScreenState extends State<MobileLoginScreen> {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
Container(
|
SlideFadeEntrance(
|
||||||
|
delay: const Duration(milliseconds: 200),
|
||||||
|
child: Container(
|
||||||
padding: const EdgeInsets.all(20),
|
padding: const EdgeInsets.all(20),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: const Color(0xFFF3F3F3),
|
color: const Color(0xFFF3F3F3),
|
||||||
|
|
@ -446,9 +458,15 @@ class _MobileLoginScreenState extends State<MobileLoginScreen> {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
|
||||||
SizedBox(height: gap),
|
SizedBox(height: gap),
|
||||||
|
|
||||||
|
SlideFadeEntrance(
|
||||||
|
delay: const Duration(milliseconds: 300),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
const Expanded(child: Divider(color: Color(0xFFE4BEBA))),
|
const Expanded(child: Divider(color: Color(0xFFE4BEBA))),
|
||||||
|
|
@ -466,9 +484,7 @@ class _MobileLoginScreenState extends State<MobileLoginScreen> {
|
||||||
const Expanded(child: Divider(color: Color(0xFFE4BEBA))),
|
const Expanded(child: Divider(color: Color(0xFFE4BEBA))),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
||||||
SizedBox(height: gap),
|
SizedBox(height: gap),
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
'Mobile Number',
|
'Mobile Number',
|
||||||
style: theme.textTheme.labelSmall?.copyWith(
|
style: theme.textTheme.labelSmall?.copyWith(
|
||||||
|
|
@ -477,7 +493,6 @@ class _MobileLoginScreenState extends State<MobileLoginScreen> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
|
|
||||||
Container(
|
Container(
|
||||||
height: 56,
|
height: 56,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
|
|
@ -541,7 +556,6 @@ class _MobileLoginScreenState extends State<MobileLoginScreen> {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: TextField(
|
child: TextField(
|
||||||
controller: _controller,
|
controller: _controller,
|
||||||
|
|
@ -571,16 +585,24 @@ class _MobileLoginScreenState extends State<MobileLoginScreen> {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
SizedBox(height: gap * 2),
|
SizedBox(height: gap * 2),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
Column(
|
SlideFadeEntrance(
|
||||||
|
delay: const Duration(milliseconds: 400),
|
||||||
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
ElevatedButton(
|
InteractiveScale(
|
||||||
|
hoverScale: _isValid ? 1.03 : 1.0,
|
||||||
|
tapScale: _isValid ? 0.96 : 1.0,
|
||||||
|
child: ElevatedButton(
|
||||||
onPressed: _isValid
|
onPressed: _isValid
|
||||||
? () {
|
? () {
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
|
|
@ -599,13 +621,15 @@ class _MobileLoginScreenState extends State<MobileLoginScreen> {
|
||||||
foregroundColor: _isValid ? Colors.white : Colors.grey[400],
|
foregroundColor: _isValid ? Colors.white : Colors.grey[400],
|
||||||
elevation: _isValid ? 2 : 0,
|
elevation: _isValid ? 2 : 0,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(16),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: const Text('Send OTP'),
|
child: const Text('Send OTP'),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
SizedBox(height: gap / 2),
|
SizedBox(height: gap / 2),
|
||||||
OutlinedButton(
|
InteractiveScale(
|
||||||
|
child: OutlinedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
showTopAlert(
|
showTopAlert(
|
||||||
context,
|
context,
|
||||||
|
|
@ -617,7 +641,7 @@ class _MobileLoginScreenState extends State<MobileLoginScreen> {
|
||||||
minimumSize: const Size.fromHeight(56),
|
minimumSize: const Size.fromHeight(56),
|
||||||
side: const BorderSide(color: Color(0xFFAF101A), width: 2),
|
side: const BorderSide(color: Color(0xFFAF101A), width: 2),
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(16),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
|
|
@ -636,8 +660,10 @@ class _MobileLoginScreenState extends State<MobileLoginScreen> {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -123,8 +123,10 @@ class _OtpVerificationScreenState extends State<OtpVerificationScreen> {
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
// Alert envelope pulse symbol
|
// Alert envelope pulse symbol with SlideFadeEntrance
|
||||||
Center(
|
SlideFadeEntrance(
|
||||||
|
delay: Duration.zero,
|
||||||
|
child: Center(
|
||||||
child: Container(
|
child: Container(
|
||||||
width: 96,
|
width: 96,
|
||||||
height: 96,
|
height: 96,
|
||||||
|
|
@ -155,16 +157,22 @@ class _OtpVerificationScreenState extends State<OtpVerificationScreen> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
Text(
|
SlideFadeEntrance(
|
||||||
|
delay: const Duration(milliseconds: 100),
|
||||||
|
child: Text(
|
||||||
'Verifying your number',
|
'Verifying your number',
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: theme.textTheme.headlineMedium?.copyWith(
|
style: theme.textTheme.headlineMedium?.copyWith(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
Row(
|
SlideFadeEntrance(
|
||||||
|
delay: const Duration(milliseconds: 150),
|
||||||
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
|
|
@ -173,7 +181,7 @@ class _OtpVerificationScreenState extends State<OtpVerificationScreen> {
|
||||||
style: theme.textTheme.bodyMedium,
|
style: theme.textTheme.bodyMedium,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
GestureDetector(
|
InteractiveScale(
|
||||||
onTap: () => Navigator.pop(context),
|
onTap: () => Navigator.pop(context),
|
||||||
child: Text(
|
child: Text(
|
||||||
'Edit',
|
'Edit',
|
||||||
|
|
@ -186,11 +194,14 @@ class _OtpVerificationScreenState extends State<OtpVerificationScreen> {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 20),
|
||||||
|
|
||||||
// 6 Custom Inputs Fields
|
// 6 Custom Inputs Fields with SlideFadeEntrance
|
||||||
Row(
|
SlideFadeEntrance(
|
||||||
|
delay: const Duration(milliseconds: 200),
|
||||||
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: List.generate(11, (index) {
|
children: List.generate(11, (index) {
|
||||||
if (index.isOdd) {
|
if (index.isOdd) {
|
||||||
|
|
@ -213,11 +224,11 @@ class _OtpVerificationScreenState extends State<OtpVerificationScreen> {
|
||||||
counterText: '',
|
counterText: '',
|
||||||
contentPadding: const EdgeInsets.symmetric(vertical: 12),
|
contentPadding: const EdgeInsets.symmetric(vertical: 12),
|
||||||
enabledBorder: OutlineInputBorder(
|
enabledBorder: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(12),
|
||||||
borderSide: BorderSide(color: theme.colorScheme.outlineVariant),
|
borderSide: BorderSide(color: theme.colorScheme.outlineVariant),
|
||||||
),
|
),
|
||||||
focusedBorder: OutlineInputBorder(
|
focusedBorder: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(12),
|
||||||
borderSide: BorderSide(color: theme.colorScheme.primary, width: 2),
|
borderSide: BorderSide(color: theme.colorScheme.primary, width: 2),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -230,15 +241,18 @@ class _OtpVerificationScreenState extends State<OtpVerificationScreen> {
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 24),
|
||||||
|
|
||||||
// Auto detect loader
|
// Auto detect loader card with SlideFadeEntrance
|
||||||
Container(
|
SlideFadeEntrance(
|
||||||
|
delay: const Duration(milliseconds: 250),
|
||||||
|
child: Container(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
|
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: theme.colorScheme.surfaceContainerLow,
|
color: theme.colorScheme.surfaceContainerLow,
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(16),
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
|
@ -261,11 +275,14 @@ class _OtpVerificationScreenState extends State<OtpVerificationScreen> {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 24),
|
||||||
|
|
||||||
// Resending timer action column
|
// Resending timer action row
|
||||||
Row(
|
SlideFadeEntrance(
|
||||||
|
delay: const Duration(milliseconds: 300),
|
||||||
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.schedule, size: 16, color: Colors.grey),
|
const Icon(Icons.schedule, size: 16, color: Colors.grey),
|
||||||
|
|
@ -278,29 +295,40 @@ class _OtpVerificationScreenState extends State<OtpVerificationScreen> {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
// WhatsApp custom CTA button
|
// WhatsApp custom CTA button with InteractiveScale
|
||||||
ElevatedButton(
|
SlideFadeEntrance(
|
||||||
onPressed: () {},
|
delay: const Duration(milliseconds: 350),
|
||||||
style: ElevatedButton.styleFrom(
|
child: InteractiveScale(
|
||||||
backgroundColor: Colors.white,
|
child: OutlinedButton.icon(
|
||||||
foregroundColor: Colors.black87,
|
onPressed: () {
|
||||||
side: const BorderSide(color: Color(0xFFE2E2E2)),
|
showTopAlert(
|
||||||
elevation: 1,
|
context,
|
||||||
minimumSize: const Size(200, 48),
|
'WhatsApp verification request sent!',
|
||||||
),
|
icon: Icons.chat_bubble_outline,
|
||||||
child: Row(
|
);
|
||||||
mainAxisSize: MainAxisSize.min,
|
},
|
||||||
children: const [
|
icon: const Icon(Icons.forum, color: Colors.green, size: 18),
|
||||||
Text(
|
label: const Text(
|
||||||
'Resend via WhatsApp',
|
'Resend via WhatsApp',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.black87,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
style: OutlinedButton.styleFrom(
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
side: const BorderSide(color: Color(0xFFE2E2E2)),
|
||||||
|
elevation: 1,
|
||||||
|
minimumSize: const Size(220, 48),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
|
@ -326,9 +354,22 @@ class _OtpVerificationScreenState extends State<OtpVerificationScreen> {
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
children: [
|
children: [
|
||||||
_buildFooterAction(Icons.help_outline, 'Help'),
|
_buildFooterAction(Icons.help_outline, 'Help', () {
|
||||||
_buildFooterAction(Icons.save, 'Save Draft'),
|
showTopAlert(
|
||||||
TextButton.icon(
|
context,
|
||||||
|
'Support agent contacted. We will call you shortly.',
|
||||||
|
icon: Icons.support_agent_outlined,
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
_buildFooterAction(Icons.save, 'Save Draft', () {
|
||||||
|
showTopAlert(
|
||||||
|
context,
|
||||||
|
'Onboarding draft saved successfully!',
|
||||||
|
icon: Icons.save_outlined,
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
InteractiveScale(
|
||||||
|
child: TextButton.icon(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
|
|
@ -347,7 +388,8 @@ class _OtpVerificationScreenState extends State<OtpVerificationScreen> {
|
||||||
backgroundColor: theme.colorScheme.primary,
|
backgroundColor: theme.colorScheme.primary,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
@ -363,8 +405,10 @@ class _OtpVerificationScreenState extends State<OtpVerificationScreen> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildFooterAction(IconData icon, String label) {
|
Widget _buildFooterAction(IconData icon, String label, VoidCallback onTap) {
|
||||||
return Column(
|
return InteractiveScale(
|
||||||
|
onTap: onTap,
|
||||||
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Icon(icon, color: Colors.grey[600], size: 22),
|
Icon(icon, color: Colors.grey[600], size: 22),
|
||||||
|
|
@ -378,6 +422,7 @@ class _OtpVerificationScreenState extends State<OtpVerificationScreen> {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,6 @@ class _SetupCompleteScreenState extends State<SetupCompleteScreen> with SingleTi
|
||||||
late Animation<double> _cardOpacityAnimation;
|
late Animation<double> _cardOpacityAnimation;
|
||||||
late Animation<double> _btnSlideAnimation;
|
late Animation<double> _btnSlideAnimation;
|
||||||
late Animation<double> _btnOpacityAnimation;
|
late Animation<double> _btnOpacityAnimation;
|
||||||
double _btnScale = 1.0;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
|
@ -382,16 +381,7 @@ class _SetupCompleteScreenState extends State<SetupCompleteScreen> with SingleTi
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
child: MouseRegion(
|
child: InteractiveScale(
|
||||||
onEnter: (_) => setState(() => _btnScale = 1.03),
|
|
||||||
onExit: (_) => setState(() => _btnScale = 1.0),
|
|
||||||
child: AnimatedScale(
|
|
||||||
scale: _btnScale,
|
|
||||||
duration: const Duration(milliseconds: 150),
|
|
||||||
child: GestureDetector(
|
|
||||||
onTapDown: (_) => setState(() => _btnScale = 0.96),
|
|
||||||
onTapUp: (_) => setState(() => _btnScale = 1.03),
|
|
||||||
onTapCancel: () => setState(() => _btnScale = 1.0),
|
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
showTopAlert(
|
showTopAlert(
|
||||||
|
|
@ -416,7 +406,7 @@ class _SetupCompleteScreenState extends State<SetupCompleteScreen> with SingleTi
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
minimumSize: const Size.fromHeight(56),
|
minimumSize: const Size.fromHeight(56),
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(16),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
|
|
@ -430,8 +420,6 @@ class _SetupCompleteScreenState extends State<SetupCompleteScreen> with SingleTi
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ class _WelcomeScreenState extends State<WelcomeScreen> with SingleTickerProvider
|
||||||
late Animation<double> _splashContainerOpacityAnimation;
|
late Animation<double> _splashContainerOpacityAnimation;
|
||||||
late Animation<double> _contentFadeAnimation;
|
late Animation<double> _contentFadeAnimation;
|
||||||
late Animation<Offset> _contentSlideAnimation;
|
late Animation<Offset> _contentSlideAnimation;
|
||||||
double _btnScale = 1.0;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
|
@ -491,17 +490,7 @@ class _WelcomeScreenState extends State<WelcomeScreen> with SingleTickerProvider
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: context.isMobile ? CrossAxisAlignment.center : CrossAxisAlignment.start,
|
crossAxisAlignment: context.isMobile ? CrossAxisAlignment.center : CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
MouseRegion(
|
InteractiveScale(
|
||||||
onEnter: (_) => setState(() => _btnScale = 1.03),
|
|
||||||
onExit: (_) => setState(() => _btnScale = 1.0),
|
|
||||||
child: GestureDetector(
|
|
||||||
onTapDown: (_) => setState(() => _btnScale = 0.95),
|
|
||||||
onTapUp: (_) => setState(() => _btnScale = 1.03),
|
|
||||||
onTapCancel: () => setState(() => _btnScale = 1.0),
|
|
||||||
child: AnimatedScale(
|
|
||||||
scale: _btnScale,
|
|
||||||
duration: const Duration(milliseconds: 150),
|
|
||||||
curve: Curves.easeOut,
|
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
|
|
@ -523,8 +512,6 @@ class _WelcomeScreenState extends State<WelcomeScreen> with SingleTickerProvider
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: context.isMobile ? MainAxisAlignment.center : MainAxisAlignment.start,
|
mainAxisAlignment: context.isMobile ? MainAxisAlignment.center : MainAxisAlignment.start,
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,7 @@ class PozoTheme {
|
||||||
minimumSize: const Size.fromHeight(54),
|
minimumSize: const Size.fromHeight(54),
|
||||||
elevation: 2,
|
elevation: 2,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(16),
|
||||||
),
|
),
|
||||||
textStyle: GoogleFonts.plusJakartaSans(
|
textStyle: GoogleFonts.plusJakartaSans(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
|
|
|
||||||
|
|
@ -41,14 +41,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.19.1"
|
version: "1.19.1"
|
||||||
contacts_service:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: contacts_service
|
|
||||||
sha256: f6d5ea33b31dfcdcd2e65d8abdc836502e04ddb0f66a96aa726fa9891ea9671e
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.6.3"
|
|
||||||
cross_file:
|
cross_file:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -126,6 +118,14 @@ packages:
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
flutter_contacts:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_contacts
|
||||||
|
sha256: "388d32cd33f16640ee169570128c933b45f3259bddbfae7a100bb49e5ffea9ae"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.9+2"
|
||||||
flutter_lints:
|
flutter_lints:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
|
|
@ -424,14 +424,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.8"
|
version: "2.1.8"
|
||||||
quiver:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: quiver
|
|
||||||
sha256: ea0b925899e64ecdfbf9c7becb60d5b50e706ade44a85b2363be2a22d88117d2
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "3.2.2"
|
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ dependencies:
|
||||||
google_fonts: ^5.1.0
|
google_fonts: ^5.1.0
|
||||||
image_picker: ^1.0.4
|
image_picker: ^1.0.4
|
||||||
permission_handler: ^11.0.1
|
permission_handler: ^11.0.1
|
||||||
contacts_service: ^0.6.3
|
flutter_contacts: ^1.1.9
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue