import 'dart:typed_data'; import 'dart:ui' show ImageFilter; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:inventory_app/constants.dart'; // ── Gradient background ─────────────────────────────────────────────────────── class FancyBackground extends StatelessWidget { const FancyBackground({super.key}); @override Widget build(BuildContext context) { final dark = Theme.of(context).brightness == Brightness.dark; return DecoratedBox( decoration: BoxDecoration( gradient: LinearGradient( colors: dark ? [ const Color(0xFF0A0A0A), const Color(0xFF121212), const Color(0xFF1E1E1E), ] : [ const Color(0xFFEEF2FF), const Color(0xFFE0F2FE), const Color(0xFFE6FFFA), ], begin: Alignment.topLeft, end: Alignment.bottomRight, ), ), child: Stack( children: [ Positioned( top: -60, right: -40, child: _Blob( color: dark ? Colors.blue.withOpacity(0.1) : Colors.blue.withOpacity(0.18), size: 170, ), ), Positioned( bottom: -40, left: -40, child: _Blob( color: dark ? Colors.cyanAccent.withOpacity(0.08) : Colors.cyan.withOpacity(0.16), size: 150, ), ), ], ), ); } } class _Blob extends StatelessWidget { final Color color; final double size; const _Blob({required this.color, required this.size}); @override Widget build(BuildContext context) { return Container( width: size, height: size, decoration: BoxDecoration( shape: BoxShape.circle, color: color, boxShadow: [BoxShadow(color: color, blurRadius: 60, spreadRadius: 30)], ), ); } } // ── Glass card ──────────────────────────────────────────────────────────────── class GlassCard extends StatelessWidget { final Widget child; final EdgeInsets? padding; const GlassCard({super.key, required this.child, this.padding}); @override Widget build(BuildContext context) { final dark = Theme.of(context).brightness == Brightness.dark; return Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(20), gradient: LinearGradient( colors: dark ? [ Colors.white.withOpacity(0.06), Colors.white.withOpacity(0.03), ] : [ Colors.white.withOpacity(0.42), Colors.white.withOpacity(0.18), ], begin: Alignment.topLeft, end: Alignment.bottomRight, ), border: Border.all( color: dark ? Colors.white.withOpacity(0.08) : Colors.white.withOpacity(0.5), ), boxShadow: [ BoxShadow( color: dark ? Colors.black.withOpacity(0.4) : Colors.blueGrey.withOpacity(0.15), blurRadius: 18, offset: const Offset(0, 10), ), ], ), child: ClipRRect( borderRadius: BorderRadius.circular(20), child: BackdropFilter( filter: ImageFilter.blur(sigmaX: 14, sigmaY: 14), child: Padding( padding: padding ?? const EdgeInsets.all(16), child: child, ), ), ), ); } } // ── App bar for sub-pages (with back button) ────────────────────────────────── class BackAppBar extends StatelessWidget { final String title; final IconData? icon; final List? actions; const BackAppBar({super.key, required this.title, this.icon, this.actions}); @override Widget build(BuildContext context) { final isDark = Theme.of(context).brightness == Brightness.dark; return Padding( padding: const EdgeInsets.fromLTRB(12, 8, 12, 10), child: GlassCard( padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 6), child: Row( children: [ IconButton( icon: const Icon(Icons.arrow_back_rounded), onPressed: () => Get.back(), color: isDark ? Colors.white70 : Colors.black87, ), if (icon != null) Icon(icon!, color: Colors.blue), if (icon != null) const SizedBox(width: 8), Expanded( child: Text( title, overflow: TextOverflow.ellipsis, style: TextStyle( fontSize: 18, fontWeight: FontWeight.w800, color: isDark ? Colors.white : Colors.blue.shade700, ), ), ), if (actions != null) ...actions!, ], ), ), ); } } // ── Glass bottom sheet ──────────────────────────────────────────────────────── class GlassBottomSheet extends StatelessWidget { final Widget child; const GlassBottomSheet({super.key, required this.child}); @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.all(12), child: GlassCard(child: child), ); } } class SheetHandle extends StatelessWidget { final Color color; const SheetHandle(this.color, {super.key}); @override Widget build(BuildContext context) { return Center( child: Container( width: 50, height: 6, margin: const EdgeInsets.symmetric(vertical: 12), decoration: BoxDecoration( color: color.withOpacity(.4), borderRadius: BorderRadius.circular(10), ), ), ); } } // ── Text field ──────────────────────────────────────────────────────────────── class AppTextField extends StatelessWidget { final TextEditingController controller; final String label; final bool enabled; final IconData? icon; final TextInputType? type; const AppTextField({ super.key, required this.controller, required this.label, this.enabled = true, this.icon, this.type, }); @override Widget build(BuildContext context) { final dark = Theme.of(context).brightness == Brightness.dark; return TextField( controller: controller, enabled: enabled, keyboardType: type, style: kTextFormFieldStyle( color: dark ? Colors.white.withOpacity(.9) : Colors.black87, ), decoration: InputDecoration( labelText: label, prefixIcon: icon != null ? Icon(icon, color: dark ? Colors.white70 : Colors.black54) : null, filled: true, fillColor: dark ? Colors.white12 : Colors.white.withOpacity(.8), border: OutlineInputBorder( borderRadius: BorderRadius.circular(16), borderSide: BorderSide.none, ), ), ); } } class FancyTextField extends StatelessWidget { final TextEditingController controller; final String label; final String hint; final IconData icon; final int maxLines; final String? Function(String?)? validator; const FancyTextField({ super.key, required this.controller, required this.label, required this.hint, required this.icon, this.maxLines = 1, this.validator, }); @override Widget build(BuildContext context) { final border = OutlineInputBorder( borderRadius: BorderRadius.circular(16), borderSide: BorderSide.none, ); final isDark = Theme.of(context).brightness == Brightness.dark; return TextFormField( controller: controller, maxLines: maxLines, validator: validator, style: TextStyle( color: isDark ? Colors.white.withOpacity(0.9) : Colors.black87, ), decoration: InputDecoration( labelText: label, hintText: hint, prefixIcon: Icon(icon, color: isDark ? Colors.white70 : Colors.black54), filled: true, fillColor: isDark ? Colors.white.withOpacity(0.08) : Colors.white.withOpacity(0.75), enabledBorder: border, focusedBorder: border, ), ); } } // ── Dropdown ────────────────────────────────────────────────────────────────── class AppDropdown extends StatelessWidget { final T? value; final List items; final String hint; final String Function(T) labelBuilder; final ValueChanged onChanged; const AppDropdown({ super.key, required this.value, required this.items, required this.hint, required this.labelBuilder, required this.onChanged, }); @override Widget build(BuildContext context) { final dark = Theme.of(context).brightness == Brightness.dark; return DropdownButtonFormField( value: value, isExpanded: true, items: items .map( (e) => DropdownMenuItem( value: e, child: Text( labelBuilder(e), overflow: TextOverflow.ellipsis, style: kTextFormFieldStyle( color: dark ? Colors.white : Colors.black87, ), ), ), ) .toList(), onChanged: onChanged, decoration: InputDecoration( labelText: hint, filled: true, fillColor: dark ? Colors.white12 : Colors.white.withOpacity(.8), border: OutlineInputBorder(borderRadius: BorderRadius.circular(16)), ), ); } } // ── Image loader ────────────────────────────────────────────────────────────── class AppImage extends StatelessWidget { final Future future; const AppImage({super.key, required this.future}); @override Widget build(BuildContext context) { return FutureBuilder( future: future, builder: (_, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const GlassCard( child: Center( child: Padding( padding: EdgeInsets.all(12), child: CircularProgressIndicator(), ), ), ); } if (!snapshot.hasData) return const SizedBox.shrink(); return GlassCard( padding: EdgeInsets.zero, child: ClipRRect( borderRadius: BorderRadius.circular(20), child: Image.memory( snapshot.data!, height: 200, width: double.infinity, fit: BoxFit.cover, ), ), ); }, ); } } // ── Section header ──────────────────────────────────────────────────────────── class SectionHeader extends StatelessWidget { final IconData icon; final String title; final Color accent; const SectionHeader({ super.key, required this.icon, required this.title, required this.accent, }); @override Widget build(BuildContext context) { return Row( children: [ Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: accent.withOpacity(.15), borderRadius: BorderRadius.circular(12), ), child: Icon(icon, color: accent), ), const SizedBox(width: 10), Text( title, style: kTextFormFieldStyle( fontSize: 18.0, fontWeight: FontWeight.w700, color: Colors.blue.shade700, ), ), ], ); } } class SubLabel extends StatelessWidget { final String text; final MaterialColor color; const SubLabel(this.text, this.color, {super.key}); @override Widget build(BuildContext context) { return Text( text, style: kTextFormFieldStyle( fontSize: 14.0, fontWeight: FontWeight.w600, color: color.shade700, ), ); } } // ── Radio tile ──────────────────────────────────────────────────────────────── class TileRadio extends StatelessWidget { final String value; final String? groupValue; final String label; final IconData icon; final ValueChanged onChanged; const TileRadio({ super.key, required this.value, required this.groupValue, required this.label, required this.icon, required this.onChanged, }); @override Widget build(BuildContext context) { final selected = value == groupValue; return AnimatedContainer( duration: const Duration(milliseconds: 200), margin: const EdgeInsets.symmetric(vertical: 6), decoration: BoxDecoration( color: selected ? Colors.white.withOpacity(.85) : Colors.white.withOpacity(.6), borderRadius: BorderRadius.circular(14), border: Border.all( color: selected ? Colors.blue.withOpacity(.6) : Colors.white.withOpacity(.4), ), ), child: ListTile( leading: Icon(icon, color: selected ? Colors.blue : Colors.black54), title: Text(label, style: kTextFormFieldStyle()), trailing: Radio( value: value, groupValue: groupValue, onChanged: onChanged, ), onTap: () => onChanged(value), ), ); } } // ── FAB ─────────────────────────────────────────────────────────────────────── class FancyFAB extends StatelessWidget { final Color primary; final VoidCallback onTap; const FancyFAB({super.key, required this.primary, required this.onTap}); @override Widget build(BuildContext context) { return Container( decoration: BoxDecoration( gradient: LinearGradient(colors: [primary, primary.withOpacity(.8)]), borderRadius: BorderRadius.circular(28), boxShadow: [ BoxShadow( color: primary.withOpacity(.35), blurRadius: 24, offset: const Offset(0, 10), ), ], ), child: FloatingActionButton.extended( backgroundColor: Colors.transparent, elevation: 0, onPressed: onTap, icon: const Icon(Icons.document_scanner, color: Colors.white), label: const Text("Scanner", style: TextStyle(color: Colors.white)), ), ); } }