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 {
|
||||
val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
|
||||
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 {
|
||||
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),
|
||||
child: Directionality(
|
||||
textDirection: TextDirection.rtl,
|
||||
child: InteractiveScale(
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: _simulateBarcodeScan,
|
||||
style: ElevatedButton.styleFrom(
|
||||
|
|
@ -267,6 +268,7 @@ class _BillingDashboardScreenState extends State<BillingDashboardScreen> {
|
|||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (widget.kotManagement)
|
||||
Container(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 4, vertical: 12),
|
||||
|
|
@ -407,7 +409,13 @@ class _BillingDashboardScreenState extends State<BillingDashboardScreen> {
|
|||
final isLowStock = widget.inventoryAlerts && remainingStock <= 3;
|
||||
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),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
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),
|
||||
_buildComputationCalculations(theme),
|
||||
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,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: theme.colorScheme.primary,
|
||||
disabledBackgroundColor: const Color(0xFF1E293B),
|
||||
minimumSize: const Size.fromHeight(48),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
),
|
||||
child: const Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
|
|
@ -670,6 +686,7 @@ class _BillingDashboardScreenState extends State<BillingDashboardScreen> {
|
|||
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,
|
||||
style: ElevatedButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
|
||||
minimumSize: const Size(180, 44),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
),
|
||||
child: const Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
|
|
@ -765,6 +788,7 @@ class _BillingDashboardScreenState extends State<BillingDashboardScreen> {
|
|||
Text('Review & Invoice', style: TextStyle(fontSize: 12)),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
|
|
@ -937,7 +961,8 @@ class _BillingDashboardScreenState extends State<BillingDashboardScreen> {
|
|||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
ElevatedButton.icon(
|
||||
InteractiveScale(
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: () {
|
||||
showTopAlert(
|
||||
context,
|
||||
|
|
@ -951,17 +976,26 @@ class _BillingDashboardScreenState extends State<BillingDashboardScreen> {
|
|||
backgroundColor: Colors.black,
|
||||
foregroundColor: Colors.white,
|
||||
minimumSize: const Size.fromHeight(42),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
ElevatedButton(
|
||||
InteractiveScale(
|
||||
child: ElevatedButton(
|
||||
onPressed: _closeReceiptAndReset,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: theme.colorScheme.primary,
|
||||
minimumSize: const Size.fromHeight(42),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
),
|
||||
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) {
|
||||
final theme = Theme.of(context);
|
||||
final isSelected = _selectedDocs.contains(label);
|
||||
return InkWell(
|
||||
return InteractiveScale(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
if (isSelected) {
|
||||
|
|
@ -188,6 +189,7 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
|||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -337,7 +339,8 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
|||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
ElevatedButton.icon(
|
||||
InteractiveScale(
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: () => _handleImagePick(docName, ImageSource.camera),
|
||||
icon: const Icon(Icons.camera_alt, size: 14),
|
||||
label: const Text('Take Photo'),
|
||||
|
|
@ -348,11 +351,13 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
|||
elevation: 1,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8)),
|
||||
borderRadius: BorderRadius.circular(16)),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
OutlinedButton.icon(
|
||||
InteractiveScale(
|
||||
child: OutlinedButton.icon(
|
||||
onPressed: () => _handleImagePick(docName, ImageSource.gallery),
|
||||
icon: const Icon(Icons.photo_library, size: 14),
|
||||
label: const Text('From Gallery'),
|
||||
|
|
@ -361,7 +366,8 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
|||
side: const BorderSide(color: Color(0xFFAF101A)),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8)),
|
||||
borderRadius: BorderRadius.circular(16)),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
|
@ -438,6 +444,11 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
|||
physics: const BouncingScrollPhysics(),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SlideFadeEntrance(
|
||||
delay: Duration.zero,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
|
|
@ -452,8 +463,16 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
|||
'Verify your business details to start selling.',
|
||||
style: theme.textTheme.bodyMedium,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
SlideFadeEntrance(
|
||||
delay: const Duration(milliseconds: 100),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Business/Shop Name *',
|
||||
style: theme.textTheme.labelSmall?.copyWith(
|
||||
|
|
@ -469,8 +488,16 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
|||
),
|
||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
SlideFadeEntrance(
|
||||
delay: const Duration(milliseconds: 180),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Business Type *',
|
||||
style: theme.textTheme.labelSmall?.copyWith(
|
||||
|
|
@ -479,7 +506,6 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
|||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
|
||||
GridView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
|
|
@ -494,7 +520,8 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
|||
final cat = _categories[index];
|
||||
final isSelected = _selectedCategory == cat['id'];
|
||||
|
||||
return InkWell(
|
||||
return InteractiveScale(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
_selectedCategory = cat['id'];
|
||||
|
|
@ -545,11 +572,20 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
|||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
SlideFadeEntrance(
|
||||
delay: const Duration(milliseconds: 260),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
|
|
@ -583,7 +619,8 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
|||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
ElevatedButton(
|
||||
InteractiveScale(
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
showTopAlert(
|
||||
context,
|
||||
|
|
@ -602,6 +639,7 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
|||
),
|
||||
child: const Text('Verify'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
|
|
@ -609,8 +647,16 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
|||
"Auto-fetches address & legal name on verification.",
|
||||
style: TextStyle(fontSize: 11, color: Colors.grey[500]),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
SlideFadeEntrance(
|
||||
delay: const Duration(milliseconds: 340),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Shop Location *',
|
||||
style: theme.textTheme.labelSmall?.copyWith(
|
||||
|
|
@ -619,7 +665,8 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
|||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
InkWell(
|
||||
InteractiveScale(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
showTopAlert(
|
||||
context,
|
||||
|
|
@ -683,8 +730,17 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
|||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
SlideFadeEntrance(
|
||||
delay: const Duration(milliseconds: 420),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Identity / License Documents (Select all that apply)',
|
||||
style: theme.textTheme.labelSmall?.copyWith(
|
||||
|
|
@ -704,8 +760,15 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
|||
_buildDocChip('PAN', Icons.credit_card),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
..._selectedDocs.map((doc) {
|
||||
|
||||
SlideFadeEntrance(
|
||||
delay: const Duration(milliseconds: 500),
|
||||
child: Column(
|
||||
children: _selectedDocs.map((doc) {
|
||||
IconData docIcon = Icons.description;
|
||||
if (doc == 'GSTIN') docIcon = Icons.description;
|
||||
if (doc == 'FSSAI') docIcon = Icons.restaurant;
|
||||
|
|
@ -713,9 +776,16 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
|||
if (doc == 'Udhyog Aadhar') docIcon = Icons.domain;
|
||||
if (doc == 'PAN') docIcon = Icons.credit_card;
|
||||
return _buildUploadSection(doc, docIcon);
|
||||
}),
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
SlideFadeEntrance(
|
||||
delay: const Duration(milliseconds: 580),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Shop Facade Photo *',
|
||||
style: theme.textTheme.labelSmall?.copyWith(
|
||||
|
|
@ -724,10 +794,12 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
|||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
InkWell(
|
||||
InteractiveScale(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
_showFacadePhotoOptions();
|
||||
},
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.symmetric(vertical: 24),
|
||||
|
|
@ -774,6 +846,10 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
|||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
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),
|
||||
child: InteractiveScale(
|
||||
hoverScale: _isNameValid ? 1.03 : 1.0,
|
||||
tapScale: _isNameValid ? 0.96 : 1.0,
|
||||
child: ElevatedButton(
|
||||
onPressed: _isNameValid
|
||||
? () {
|
||||
|
|
@ -803,9 +884,14 @@ class _BusinessSetupScreenState extends State<BusinessSetupScreen> {
|
|||
backgroundColor: _isNameValid ? theme.colorScheme.primary : Colors.grey[200],
|
||||
foregroundColor: _isNameValid ? Colors.white : Colors.grey[400],
|
||||
elevation: _isNameValid ? 2 : 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
),
|
||||
child: const Text('Continue to Verification'),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
|
|
|
|||
|
|
@ -116,6 +116,11 @@ class _CustomizeSetupScreenState extends State<CustomizeSetupScreen> {
|
|||
physics: const BouncingScrollPhysics(),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SlideFadeEntrance(
|
||||
delay: Duration.zero,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
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.',
|
||||
style: theme.textTheme.bodyMedium,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// Toggle 1: Barcode
|
||||
_buildToggleCard(
|
||||
SlideFadeEntrance(
|
||||
delay: const Duration(milliseconds: 100),
|
||||
child: _buildToggleCard(
|
||||
Icons.qr_code_scanner,
|
||||
'Barcode Scanner',
|
||||
'Do you use a Barcode Scanner?',
|
||||
|
|
@ -141,10 +151,13 @@ class _CustomizeSetupScreenState extends State<CustomizeSetupScreen> {
|
|||
(val) => setState(() => _barcode = val),
|
||||
theme,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
|
||||
// Toggle 2: KOT
|
||||
_buildToggleCard(
|
||||
SlideFadeEntrance(
|
||||
delay: const Duration(milliseconds: 180),
|
||||
child: _buildToggleCard(
|
||||
Icons.receipt_long,
|
||||
'KOT Management',
|
||||
'Do you need Kitchen Order Ticket management?',
|
||||
|
|
@ -152,10 +165,13 @@ class _CustomizeSetupScreenState extends State<CustomizeSetupScreen> {
|
|||
(val) => setState(() => _kot = val),
|
||||
theme,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
|
||||
// Toggle 3: Inventory stock tracking
|
||||
_buildToggleCard(
|
||||
SlideFadeEntrance(
|
||||
delay: const Duration(milliseconds: 260),
|
||||
child: _buildToggleCard(
|
||||
Icons.inventory_2,
|
||||
'Inventory Alerts',
|
||||
'Get notified when stock is running low.',
|
||||
|
|
@ -163,6 +179,7 @@ class _CustomizeSetupScreenState extends State<CustomizeSetupScreen> {
|
|||
(val) => setState(() => _inventory = val),
|
||||
theme,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
@ -170,8 +187,11 @@ class _CustomizeSetupScreenState extends State<CustomizeSetupScreen> {
|
|||
),
|
||||
|
||||
// Pinned action keys
|
||||
Padding(
|
||||
SlideFadeEntrance(
|
||||
delay: const Duration(milliseconds: 340),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(padding),
|
||||
child: InteractiveScale(
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
|
|
@ -190,9 +210,14 @@ class _CustomizeSetupScreenState extends State<CustomizeSetupScreen> {
|
|||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
minimumSize: const Size.fromHeight(54),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
),
|
||||
child: const Text('Save & Continue'),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
|
|
@ -210,7 +235,9 @@ class _CustomizeSetupScreenState extends State<CustomizeSetupScreen> {
|
|||
ValueChanged<bool> onChanged,
|
||||
ThemeData theme,
|
||||
) {
|
||||
return Container(
|
||||
return InteractiveScale(
|
||||
onTap: () => onChanged(!value),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
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/foundation.dart' show kIsWeb;
|
||||
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 '../route_transitions.dart';
|
||||
import 'otp_verification_screen.dart';
|
||||
|
|
@ -16,8 +16,8 @@ class MockContact {
|
|||
}
|
||||
|
||||
class MockPhone {
|
||||
final String? value;
|
||||
MockPhone(this.value);
|
||||
final String number;
|
||||
MockPhone(this.number);
|
||||
}
|
||||
|
||||
class MobileLoginScreen extends StatefulWidget {
|
||||
|
|
@ -103,7 +103,7 @@ class _MobileLoginScreenState extends State<MobileLoginScreen> {
|
|||
];
|
||||
} else {
|
||||
try {
|
||||
final List<Contact> list = await ContactsService.getContacts(withThumbnails: false);
|
||||
final List<Contact> list = await FlutterContacts.getContacts(withProperties: true, withPhoto: false);
|
||||
return list;
|
||||
} catch (e) {
|
||||
return [];
|
||||
|
|
@ -166,7 +166,7 @@ class _MobileLoginScreenState extends State<MobileLoginScreen> {
|
|||
setDialogState(() {
|
||||
filteredContacts = allContacts.where((contact) {
|
||||
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());
|
||||
}).toList();
|
||||
});
|
||||
|
|
@ -183,7 +183,7 @@ class _MobileLoginScreenState extends State<MobileLoginScreen> {
|
|||
itemBuilder: (context, index) {
|
||||
final contact = filteredContacts[index];
|
||||
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(
|
||||
title: Text(name),
|
||||
subtitle: Text(phone),
|
||||
|
|
@ -253,6 +253,11 @@ class _MobileLoginScreenState extends State<MobileLoginScreen> {
|
|||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
physics: const BouncingScrollPhysics(),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SlideFadeEntrance(
|
||||
delay: Duration.zero,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
|
|
@ -296,7 +301,6 @@ class _MobileLoginScreenState extends State<MobileLoginScreen> {
|
|||
}),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
Text(
|
||||
'Welcome Back',
|
||||
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.',
|
||||
style: theme.textTheme.bodyMedium,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
Container(
|
||||
SlideFadeEntrance(
|
||||
delay: const Duration(milliseconds: 100),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFFAFFD1).withOpacity(0.8),
|
||||
|
|
@ -332,10 +341,13 @@ class _MobileLoginScreenState extends State<MobileLoginScreen> {
|
|||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 16),
|
||||
|
||||
Container(
|
||||
SlideFadeEntrance(
|
||||
delay: const Duration(milliseconds: 200),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF3F3F3),
|
||||
|
|
@ -446,9 +458,15 @@ class _MobileLoginScreenState extends State<MobileLoginScreen> {
|
|||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(height: gap),
|
||||
|
||||
SlideFadeEntrance(
|
||||
delay: const Duration(milliseconds: 300),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
const Expanded(child: Divider(color: Color(0xFFE4BEBA))),
|
||||
|
|
@ -466,9 +484,7 @@ class _MobileLoginScreenState extends State<MobileLoginScreen> {
|
|||
const Expanded(child: Divider(color: Color(0xFFE4BEBA))),
|
||||
],
|
||||
),
|
||||
|
||||
SizedBox(height: gap),
|
||||
|
||||
Text(
|
||||
'Mobile Number',
|
||||
style: theme.textTheme.labelSmall?.copyWith(
|
||||
|
|
@ -477,7 +493,6 @@ class _MobileLoginScreenState extends State<MobileLoginScreen> {
|
|||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
|
||||
Container(
|
||||
height: 56,
|
||||
decoration: BoxDecoration(
|
||||
|
|
@ -541,7 +556,6 @@ class _MobileLoginScreenState extends State<MobileLoginScreen> {
|
|||
],
|
||||
),
|
||||
),
|
||||
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: _controller,
|
||||
|
|
@ -571,16 +585,24 @@ class _MobileLoginScreenState extends State<MobileLoginScreen> {
|
|||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: gap * 2),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
Column(
|
||||
SlideFadeEntrance(
|
||||
delay: const Duration(milliseconds: 400),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
ElevatedButton(
|
||||
InteractiveScale(
|
||||
hoverScale: _isValid ? 1.03 : 1.0,
|
||||
tapScale: _isValid ? 0.96 : 1.0,
|
||||
child: ElevatedButton(
|
||||
onPressed: _isValid
|
||||
? () {
|
||||
Navigator.push(
|
||||
|
|
@ -599,13 +621,15 @@ class _MobileLoginScreenState extends State<MobileLoginScreen> {
|
|||
foregroundColor: _isValid ? Colors.white : Colors.grey[400],
|
||||
elevation: _isValid ? 2 : 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
),
|
||||
child: const Text('Send OTP'),
|
||||
),
|
||||
),
|
||||
SizedBox(height: gap / 2),
|
||||
OutlinedButton(
|
||||
InteractiveScale(
|
||||
child: OutlinedButton(
|
||||
onPressed: () {
|
||||
showTopAlert(
|
||||
context,
|
||||
|
|
@ -617,7 +641,7 @@ class _MobileLoginScreenState extends State<MobileLoginScreen> {
|
|||
minimumSize: const Size.fromHeight(56),
|
||||
side: const BorderSide(color: Color(0xFFAF101A), width: 2),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
|
|
@ -636,8 +660,10 @@ class _MobileLoginScreenState extends State<MobileLoginScreen> {
|
|||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -123,8 +123,10 @@ class _OtpVerificationScreenState extends State<OtpVerificationScreen> {
|
|||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
// Alert envelope pulse symbol
|
||||
Center(
|
||||
// Alert envelope pulse symbol with SlideFadeEntrance
|
||||
SlideFadeEntrance(
|
||||
delay: Duration.zero,
|
||||
child: Center(
|
||||
child: Container(
|
||||
width: 96,
|
||||
height: 96,
|
||||
|
|
@ -155,16 +157,22 @@ class _OtpVerificationScreenState extends State<OtpVerificationScreen> {
|
|||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
SlideFadeEntrance(
|
||||
delay: const Duration(milliseconds: 100),
|
||||
child: Text(
|
||||
'Verifying your number',
|
||||
textAlign: TextAlign.center,
|
||||
style: theme.textTheme.headlineMedium?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
SlideFadeEntrance(
|
||||
delay: const Duration(milliseconds: 150),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
|
|
@ -173,7 +181,7 @@ class _OtpVerificationScreenState extends State<OtpVerificationScreen> {
|
|||
style: theme.textTheme.bodyMedium,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
GestureDetector(
|
||||
InteractiveScale(
|
||||
onTap: () => Navigator.pop(context),
|
||||
child: Text(
|
||||
'Edit',
|
||||
|
|
@ -186,11 +194,14 @@ class _OtpVerificationScreenState extends State<OtpVerificationScreen> {
|
|||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 16),
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// 6 Custom Inputs Fields
|
||||
Row(
|
||||
// 6 Custom Inputs Fields with SlideFadeEntrance
|
||||
SlideFadeEntrance(
|
||||
delay: const Duration(milliseconds: 200),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: List.generate(11, (index) {
|
||||
if (index.isOdd) {
|
||||
|
|
@ -213,11 +224,11 @@ class _OtpVerificationScreenState extends State<OtpVerificationScreen> {
|
|||
counterText: '',
|
||||
contentPadding: const EdgeInsets.symmetric(vertical: 12),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(color: theme.colorScheme.outlineVariant),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
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
|
||||
Container(
|
||||
// Auto detect loader card with SlideFadeEntrance
|
||||
SlideFadeEntrance(
|
||||
delay: const Duration(milliseconds: 250),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.surfaceContainerLow,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
|
|
@ -261,11 +275,14 @@ class _OtpVerificationScreenState extends State<OtpVerificationScreen> {
|
|||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 16),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Resending timer action column
|
||||
Row(
|
||||
// Resending timer action row
|
||||
SlideFadeEntrance(
|
||||
delay: const Duration(milliseconds: 300),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(Icons.schedule, size: 16, color: Colors.grey),
|
||||
|
|
@ -278,29 +295,40 @@ class _OtpVerificationScreenState extends State<OtpVerificationScreen> {
|
|||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// WhatsApp custom CTA button
|
||||
ElevatedButton(
|
||||
onPressed: () {},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.white,
|
||||
foregroundColor: Colors.black87,
|
||||
side: const BorderSide(color: Color(0xFFE2E2E2)),
|
||||
elevation: 1,
|
||||
minimumSize: const Size(200, 48),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: const [
|
||||
Text(
|
||||
// WhatsApp custom CTA button with InteractiveScale
|
||||
SlideFadeEntrance(
|
||||
delay: const Duration(milliseconds: 350),
|
||||
child: InteractiveScale(
|
||||
child: OutlinedButton.icon(
|
||||
onPressed: () {
|
||||
showTopAlert(
|
||||
context,
|
||||
'WhatsApp verification request sent!',
|
||||
icon: Icons.chat_bubble_outline,
|
||||
);
|
||||
},
|
||||
icon: const Icon(Icons.forum, color: Colors.green, size: 18),
|
||||
label: const Text(
|
||||
'Resend via WhatsApp',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
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(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
_buildFooterAction(Icons.help_outline, 'Help'),
|
||||
_buildFooterAction(Icons.save, 'Save Draft'),
|
||||
TextButton.icon(
|
||||
_buildFooterAction(Icons.help_outline, 'Help', () {
|
||||
showTopAlert(
|
||||
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: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
|
|
@ -347,7 +388,8 @@ class _OtpVerificationScreenState extends State<OtpVerificationScreen> {
|
|||
backgroundColor: theme.colorScheme.primary,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||
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) {
|
||||
return Column(
|
||||
Widget _buildFooterAction(IconData icon, String label, VoidCallback onTap) {
|
||||
return InteractiveScale(
|
||||
onTap: onTap,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
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> _btnSlideAnimation;
|
||||
late Animation<double> _btnOpacityAnimation;
|
||||
double _btnScale = 1.0;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
|
@ -382,16 +381,7 @@ class _SetupCompleteScreenState extends State<SetupCompleteScreen> with SingleTi
|
|||
),
|
||||
);
|
||||
},
|
||||
child: MouseRegion(
|
||||
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: InteractiveScale(
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
showTopAlert(
|
||||
|
|
@ -416,7 +406,7 @@ class _SetupCompleteScreenState extends State<SetupCompleteScreen> with SingleTi
|
|||
style: ElevatedButton.styleFrom(
|
||||
minimumSize: const Size.fromHeight(56),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
|
|
@ -430,8 +420,6 @@ class _SetupCompleteScreenState extends State<SetupCompleteScreen> with SingleTi
|
|||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
],
|
||||
),
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ class _WelcomeScreenState extends State<WelcomeScreen> with SingleTickerProvider
|
|||
late Animation<double> _splashContainerOpacityAnimation;
|
||||
late Animation<double> _contentFadeAnimation;
|
||||
late Animation<Offset> _contentSlideAnimation;
|
||||
double _btnScale = 1.0;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
|
@ -491,17 +490,7 @@ class _WelcomeScreenState extends State<WelcomeScreen> with SingleTickerProvider
|
|||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: context.isMobile ? CrossAxisAlignment.center : CrossAxisAlignment.start,
|
||||
children: [
|
||||
MouseRegion(
|
||||
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,
|
||||
InteractiveScale(
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
|
|
@ -523,8 +512,6 @@ class _WelcomeScreenState extends State<WelcomeScreen> with SingleTickerProvider
|
|||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
mainAxisAlignment: context.isMobile ? MainAxisAlignment.center : MainAxisAlignment.start,
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ class PozoTheme {
|
|||
minimumSize: const Size.fromHeight(54),
|
||||
elevation: 2,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
textStyle: GoogleFonts.plusJakartaSans(
|
||||
fontSize: 16,
|
||||
|
|
|
|||
|
|
@ -41,14 +41,6 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -126,6 +118,14 @@ packages:
|
|||
description: flutter
|
||||
source: sdk
|
||||
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:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
|
|
@ -424,14 +424,6 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.8"
|
||||
quiver:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: quiver
|
||||
sha256: ea0b925899e64ecdfbf9c7becb60d5b50e706ade44a85b2363be2a22d88117d2
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.2"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ dependencies:
|
|||
google_fonts: ^5.1.0
|
||||
image_picker: ^1.0.4
|
||||
permission_handler: ^11.0.1
|
||||
contacts_service: ^0.6.3
|
||||
flutter_contacts: ^1.1.9
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
|
|
|||
Loading…
Reference in New Issue