Initial commit - app-padrao-1.0

This commit is contained in:
Erik Silva
2025-12-19 23:29:24 -03:00
commit ec76d3d633
205 changed files with 13131 additions and 0 deletions

View File

@@ -0,0 +1,78 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:barber_app/core/theme/app_theme.dart';
class CustomTextField extends StatelessWidget {
final TextEditingController controller;
final String label;
final String? hint;
final IconData? prefixIcon;
final Widget? suffixIcon;
final bool obscureText;
final TextInputType? keyboardType;
final String? Function(String?)? validator;
final int maxLines;
final void Function(String)? onChanged;
final TextCapitalization textCapitalization;
final List<TextInputFormatter>? inputFormatters;
const CustomTextField({
super.key,
required this.controller,
required this.label,
this.hint,
this.prefixIcon,
this.suffixIcon,
this.obscureText = false,
this.keyboardType,
this.validator,
this.maxLines = 1,
this.onChanged,
this.textCapitalization = TextCapitalization.none,
this.inputFormatters,
});
@override
Widget build(BuildContext context) {
final isDark = Theme.of(context).brightness == Brightness.dark;
final textColor = isDark ? AppColors.textPrimary : Colors.black87;
final labelColor = isDark ? AppColors.textSecondary : Colors.black54;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: TextStyle(
color: labelColor,
fontSize: 14,
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 8),
TextFormField(
controller: controller,
obscureText: obscureText,
keyboardType: keyboardType,
validator: validator,
maxLines: maxLines,
onChanged: onChanged,
textCapitalization: textCapitalization,
inputFormatters: inputFormatters,
style: TextStyle(
color: textColor,
fontSize: 16,
),
decoration: InputDecoration(
hintText: hint,
prefixIcon: prefixIcon != null
? Icon(prefixIcon, color: labelColor)
: null,
suffixIcon: suffixIcon,
hintStyle: TextStyle(color: isDark ? Colors.white38 : Colors.black38),
),
),
],
);
}
}

View File

@@ -0,0 +1,66 @@
import 'package:flutter/material.dart';
import 'package:barber_app/core/theme/app_theme.dart';
class LoadingButton extends StatelessWidget {
final String text;
final bool isLoading;
final VoidCallback onPressed;
final Color? backgroundColor;
final Color? textColor;
final IconData? icon;
const LoadingButton({
super.key,
required this.text,
required this.isLoading,
required this.onPressed,
this.backgroundColor,
this.textColor,
this.icon,
});
@override
Widget build(BuildContext context) {
return AnimatedContainer(
duration: const Duration(milliseconds: 200),
height: 56,
child: ElevatedButton(
onPressed: isLoading ? null : onPressed,
style: ElevatedButton.styleFrom(
backgroundColor: backgroundColor ?? AppColors.primaryColor,
foregroundColor: textColor ?? AppColors.background,
disabledBackgroundColor: AppColors.primaryColor.withValues(
alpha: 0.5,
),
),
child: isLoading
? SizedBox(
width: 24,
height: 24,
child: CircularProgressIndicator(
strokeWidth: 2.5,
valueColor: AlwaysStoppedAnimation<Color>(
textColor ?? AppColors.background,
),
),
)
: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (icon != null) ...[
Icon(icon, size: 20),
const SizedBox(width: 8),
],
Text(
text,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
],
),
),
);
}
}

View File

@@ -0,0 +1,125 @@
import 'package:flutter/material.dart';
import 'package:barber_app/core/theme/app_theme.dart';
class StatCard extends StatelessWidget {
final String title;
final String value;
final IconData icon;
final Color? iconColor;
final String? subtitle;
final VoidCallback? onTap;
final bool isPrimary; // Destaque visual
const StatCard({
super.key,
required this.title,
required this.value,
required this.icon,
this.iconColor,
this.subtitle,
this.onTap,
this.isPrimary = false,
});
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,
child: Container(
height: 180, // Altura fixa para uniformidade e funcionamento do Spacer
decoration: BoxDecoration(
color: isPrimary ? AppColors.primaryColor : AppColors.surface,
gradient: isPrimary ? AppColors.goldGradient : null,
borderRadius: BorderRadius.circular(28),
boxShadow: isPrimary
? [
BoxShadow(
color: AppColors.primaryColor.withValues(alpha: 0.3),
blurRadius: 25,
offset: const Offset(0, 12),
),
]
: [
BoxShadow(
color: Colors.black.withValues(alpha: 0.2),
blurRadius: 15,
offset: const Offset(0, 8),
),
],
border: Border.all(
color: isPrimary
? Colors.white.withValues(alpha: 0.2)
: AppColors.surfaceLight,
width: 1,
),
),
padding: const EdgeInsets.all(22),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: isPrimary
? Colors.black.withValues(alpha: 0.12)
: (iconColor ?? AppColors.primaryColor).withValues(
alpha: 0.08,
),
borderRadius: BorderRadius.circular(16),
),
child: Icon(
icon,
color: isPrimary
? Colors.black
: (iconColor ?? AppColors.primaryColor),
size: 22,
),
),
if (onTap != null)
Icon(
Icons.arrow_forward_ios_rounded,
color: isPrimary
? Colors.black.withValues(alpha: 0.4)
: AppColors.textSecondary,
size: 14,
),
],
),
const Spacer(),
FittedBox(
fit: BoxFit.scaleDown,
alignment: Alignment.centerLeft,
child: Text(
value,
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.w900,
color: isPrimary ? Colors.black : AppColors.textPrimary,
fontFamily: 'Outfit',
letterSpacing: -0.5,
),
),
),
const SizedBox(height: 4),
Text(
title.toUpperCase(),
overflow: TextOverflow.ellipsis,
maxLines: 1,
style: TextStyle(
fontSize: 10,
color: isPrimary
? Colors.black.withValues(alpha: 0.6)
: AppColors.textSecondary,
fontWeight: FontWeight.w800,
letterSpacing: 1.2,
),
),
],
),
),
);
}
}