refactor: cleanup unsued files

This commit is contained in:
cogwheel0
2025-08-23 11:54:41 +05:30
parent 7f30b728ab
commit b898adbe40
19 changed files with 9 additions and 6490 deletions

View File

@@ -1,435 +0,0 @@
import 'package:flutter/material.dart';
import '../theme/theme_extensions.dart';
import 'package:flutter/services.dart';
import 'dart:io' show Platform;
/// Enhanced keyboard handling utilities for better UX
class KeyboardUtils {
KeyboardUtils._();
/// Dismiss keyboard with haptic feedback
static void dismissKeyboard(BuildContext context) {
final currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus && currentFocus.focusedChild != null) {
FocusManager.instance.primaryFocus?.unfocus();
// Add haptic feedback on iOS
if (Platform.isIOS) {
HapticFeedback.lightImpact();
}
}
}
/// Force dismiss keyboard immediately
static void forceDismissKeyboard() {
FocusManager.instance.primaryFocus?.unfocus();
SystemChannels.textInput.invokeMethod('TextInput.hide');
}
/// Check if keyboard is currently visible
static bool isKeyboardVisible(BuildContext context) {
return MediaQuery.of(context).viewInsets.bottom > 0;
}
/// Get keyboard height
static double getKeyboardHeight(BuildContext context) {
return MediaQuery.of(context).viewInsets.bottom;
}
/// Move focus to next field
static void nextFocus(BuildContext context) {
FocusScope.of(context).nextFocus();
}
/// Move focus to previous field
static void previousFocus(BuildContext context) {
FocusScope.of(context).previousFocus();
}
/// Request focus for a specific node
static void requestFocus(BuildContext context, FocusNode focusNode) {
FocusScope.of(context).requestFocus(focusNode);
}
/// Create a tap detector that dismisses keyboard when tapping outside text fields
static Widget dismissKeyboardOnTap({
required BuildContext context,
required Widget child,
}) {
return GestureDetector(
onTap: () => dismissKeyboard(context),
// Let children handle taps first (e.g., TextField gains focus)
behavior: HitTestBehavior.deferToChild,
child: child,
);
}
}
/// Widget that automatically adjusts for keyboard visibility
class KeyboardAware extends StatefulWidget {
final Widget child;
final EdgeInsets? padding;
final bool maintainBottomViewPadding;
final Duration animationDuration;
final Curve animationCurve;
const KeyboardAware({
super.key,
required this.child,
this.padding,
this.maintainBottomViewPadding = true,
this.animationDuration = const Duration(milliseconds: 250),
this.animationCurve = Curves.easeInOut,
});
@override
State<KeyboardAware> createState() => _KeyboardAwareState();
}
class _KeyboardAwareState extends State<KeyboardAware>
with WidgetsBindingObserver {
double _keyboardHeight = 0;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
void didChangeMetrics() {
super.didChangeMetrics();
final newKeyboardHeight = MediaQuery.of(context).viewInsets.bottom;
if (newKeyboardHeight != _keyboardHeight) {
setState(() {
_keyboardHeight = newKeyboardHeight;
});
}
}
@override
Widget build(BuildContext context) {
return AnimatedPadding(
duration: widget.animationDuration,
curve: widget.animationCurve,
padding: EdgeInsets.only(
bottom: widget.maintainBottomViewPadding ? _keyboardHeight : 0,
).add(widget.padding ?? EdgeInsets.zero),
child: widget.child,
);
}
}
/// Enhanced text field with better keyboard handling
class EnhancedTextField extends StatefulWidget {
final TextEditingController? controller;
final FocusNode? focusNode;
final String? hintText;
final String? labelText;
final TextInputType? keyboardType;
final TextInputAction? textInputAction;
final ValueChanged<String>? onChanged;
final ValueChanged<String>? onSubmitted;
final VoidCallback? onTap;
final bool obscureText;
final bool enabled;
final int? maxLines;
final int? minLines;
final EdgeInsets? contentPadding;
final Widget? prefixIcon;
final Widget? suffixIcon;
final bool autofocus;
final bool dismissKeyboardOnSubmit;
const EnhancedTextField({
super.key,
this.controller,
this.focusNode,
this.hintText,
this.labelText,
this.keyboardType,
this.textInputAction,
this.onChanged,
this.onSubmitted,
this.onTap,
this.obscureText = false,
this.enabled = true,
this.maxLines = 1,
this.minLines,
this.contentPadding,
this.prefixIcon,
this.suffixIcon,
this.autofocus = false,
this.dismissKeyboardOnSubmit = true,
});
@override
State<EnhancedTextField> createState() => _EnhancedTextFieldState();
}
class _EnhancedTextFieldState extends State<EnhancedTextField> {
late FocusNode _focusNode;
bool _hasFocus = false;
@override
void initState() {
super.initState();
_focusNode = widget.focusNode ?? FocusNode();
_focusNode.addListener(_onFocusChanged);
}
@override
void dispose() {
_focusNode.removeListener(_onFocusChanged);
if (widget.focusNode == null) {
_focusNode.dispose();
}
super.dispose();
}
void _onFocusChanged() {
setState(() {
_hasFocus = _focusNode.hasFocus;
});
}
void _handleSubmitted(String value) {
widget.onSubmitted?.call(value);
if (widget.dismissKeyboardOnSubmit) {
KeyboardUtils.dismissKeyboard(context);
}
// Add haptic feedback
if (Platform.isIOS) {
HapticFeedback.lightImpact();
}
}
@override
Widget build(BuildContext context) {
return AnimatedContainer(
duration: const Duration(milliseconds: 200),
decoration: BoxDecoration(
border: Border.all(
color: _hasFocus
? context.conduitTheme.buttonPrimary
: context.conduitTheme.inputBorder,
width: _hasFocus ? 2 : 1,
),
borderRadius: BorderRadius.circular(AppBorderRadius.md),
),
child: TextField(
controller: widget.controller,
focusNode: _focusNode,
obscureText: widget.obscureText,
enabled: widget.enabled,
autofocus: widget.autofocus,
keyboardType: widget.keyboardType,
textInputAction: widget.textInputAction,
maxLines: widget.maxLines,
minLines: widget.minLines,
style: TextStyle(
color: context.conduitTheme.textPrimary,
fontSize: AppTypography.bodyLarge,
),
decoration: InputDecoration(
hintText: widget.hintText,
labelText: widget.labelText,
hintStyle: TextStyle(color: context.conduitTheme.inputPlaceholder),
labelStyle: TextStyle(
color: _hasFocus
? context.conduitTheme.buttonPrimary
: context.conduitTheme.textSecondary,
),
prefixIcon: widget.prefixIcon,
suffixIcon: widget.suffixIcon,
contentPadding:
widget.contentPadding ??
const EdgeInsets.symmetric(
horizontal: Spacing.md,
vertical: Spacing.sm,
),
border: InputBorder.none,
enabledBorder: InputBorder.none,
focusedBorder: InputBorder.none,
errorBorder: InputBorder.none,
disabledBorder: InputBorder.none,
),
onChanged: widget.onChanged,
onSubmitted: _handleSubmitted,
onTap: widget.onTap,
),
);
}
}
/// Smart keyboard handler that manages multiple text fields
class SmartKeyboardHandler extends StatefulWidget {
final List<FocusNode> focusNodes;
final Widget child;
final VoidCallback? onDone;
const SmartKeyboardHandler({
super.key,
required this.focusNodes,
required this.child,
this.onDone,
});
@override
State<SmartKeyboardHandler> createState() => _SmartKeyboardHandlerState();
}
class _SmartKeyboardHandlerState extends State<SmartKeyboardHandler> {
int _currentIndex = -1;
@override
void initState() {
super.initState();
_setupFocusListeners();
}
void _setupFocusListeners() {
for (int i = 0; i < widget.focusNodes.length; i++) {
widget.focusNodes[i].addListener(() => _onFocusChanged(i));
}
}
void _onFocusChanged(int index) {
if (widget.focusNodes[index].hasFocus) {
setState(() {
_currentIndex = index;
});
}
}
void _moveToNext() {
if (_currentIndex < widget.focusNodes.length - 1) {
KeyboardUtils.requestFocus(context, widget.focusNodes[_currentIndex + 1]);
} else {
KeyboardUtils.dismissKeyboard(context);
widget.onDone?.call();
}
}
void _moveToPrevious() {
if (_currentIndex > 0) {
KeyboardUtils.requestFocus(context, widget.focusNodes[_currentIndex - 1]);
}
}
@override
Widget build(BuildContext context) {
return Focus(
onKeyEvent: (node, event) {
if (event is KeyDownEvent) {
if (event.logicalKey == LogicalKeyboardKey.tab) {
if (HardwareKeyboard.instance.isShiftPressed) {
_moveToPrevious();
} else {
_moveToNext();
}
return KeyEventResult.handled;
}
}
return KeyEventResult.ignored;
},
child: widget.child,
);
}
@override
void dispose() {
for (final focusNode in widget.focusNodes) {
focusNode.removeListener(() {});
}
super.dispose();
}
}
/// Keyboard-aware scroll view that adjusts scroll position
class KeyboardAwareScrollView extends StatefulWidget {
final ScrollController? controller;
final Widget child;
final EdgeInsets? padding;
final bool reverse;
final Duration animationDuration;
const KeyboardAwareScrollView({
super.key,
this.controller,
required this.child,
this.padding,
this.reverse = false,
this.animationDuration = const Duration(milliseconds: 300),
});
@override
State<KeyboardAwareScrollView> createState() =>
_KeyboardAwareScrollViewState();
}
class _KeyboardAwareScrollViewState extends State<KeyboardAwareScrollView>
with WidgetsBindingObserver {
late ScrollController _scrollController;
FocusNode? _currentFocus;
@override
void initState() {
super.initState();
_scrollController = widget.controller ?? ScrollController();
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
if (widget.controller == null) {
_scrollController.dispose();
}
super.dispose();
}
@override
void didChangeMetrics() {
super.didChangeMetrics();
_adjustScrollPosition();
}
void _adjustScrollPosition() {
final focus = FocusManager.instance.primaryFocus;
if (focus != null && focus != _currentFocus) {
_currentFocus = focus;
WidgetsBinding.instance.addPostFrameCallback((_) {
if (_scrollController.hasClients) {
final keyboardHeight = MediaQuery.of(context).viewInsets.bottom;
if (keyboardHeight > 0) {
_scrollController.animateTo(
_scrollController.offset + keyboardHeight / 2,
duration: widget.animationDuration,
curve: Curves.easeInOut,
);
}
}
});
}
}
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
controller: _scrollController,
reverse: widget.reverse,
padding: widget.padding,
child: widget.child,
);
}
}

View File

@@ -1,143 +0,0 @@
import 'package:flutter/material.dart';
import 'package:cached_network_image/cached_network_image.dart';
import '../theme/theme_extensions.dart';
import 'improved_loading_states.dart';
/// Cached network image widget with progressive loading and error handling
class CachedImage extends StatelessWidget {
final String imageUrl;
final double? width;
final double? height;
final BoxFit fit;
final Widget? placeholder;
final Widget? errorWidget;
final Duration fadeInDuration;
final Duration fadeOutDuration;
final bool enableMemoryCache;
final int? maxWidthDiskCache;
final int? maxHeightDiskCache;
const CachedImage({
super.key,
required this.imageUrl,
this.width,
this.height,
this.fit = BoxFit.cover,
this.placeholder,
this.errorWidget,
this.fadeInDuration = const Duration(milliseconds: 300),
this.fadeOutDuration = const Duration(milliseconds: 100),
this.enableMemoryCache = true,
this.maxWidthDiskCache,
this.maxHeightDiskCache,
});
@override
Widget build(BuildContext context) {
return CachedNetworkImage(
imageUrl: imageUrl,
width: width,
height: height,
fit: fit,
fadeInDuration: fadeInDuration,
fadeOutDuration: fadeOutDuration,
placeholder: placeholder != null
? (context, url) => placeholder!
: _buildDefaultPlaceholder,
errorWidget: errorWidget != null
? (context, url, error) => errorWidget!
: _buildDefaultErrorWidget,
memCacheWidth: enableMemoryCache ? width?.toInt() : null,
memCacheHeight: enableMemoryCache ? height?.toInt() : null,
maxWidthDiskCache: maxWidthDiskCache,
maxHeightDiskCache: maxHeightDiskCache,
useOldImageOnUrlChange: true,
filterQuality: FilterQuality.medium,
);
}
Widget _buildDefaultPlaceholder(BuildContext context, String url) {
return ShimmerLoader(
width: width ?? double.infinity,
height: height ?? 200,
borderRadius: BorderRadius.circular(8),
);
}
Widget _buildDefaultErrorWidget(
BuildContext context,
String url,
dynamic error,
) {
return Container(
width: width,
height: height,
color: context.conduitTheme.shimmerBase,
child: Icon(
Icons.broken_image,
color: context.conduitTheme.iconSecondary,
size: (width != null && height != null)
? (width! < height! ? width! * 0.5 : height! * 0.5)
: 24,
),
);
}
}
/// Cached circular avatar with progressive loading
class CachedAvatar extends StatelessWidget {
final String? imageUrl;
final String fallbackText;
final double radius;
final Color? backgroundColor;
final Color? textColor;
const CachedAvatar({
super.key,
this.imageUrl,
required this.fallbackText,
this.radius = 20,
this.backgroundColor,
this.textColor,
});
@override
Widget build(BuildContext context) {
return CircleAvatar(
radius: radius,
backgroundColor:
backgroundColor ?? context.conduitTheme.surfaceBackground,
child: imageUrl != null
? ClipOval(
child: CachedNetworkImage(
imageUrl: imageUrl!,
width: radius * 2,
height: radius * 2,
fit: BoxFit.cover,
placeholder: (context, url) => CircularProgressIndicator(
strokeWidth: 2,
color: textColor ?? context.conduitTheme.iconSecondary,
),
errorWidget: (context, url, error) => Text(
fallbackText.isNotEmpty ? fallbackText[0].toUpperCase() : '?',
style: TextStyle(
color: textColor ?? context.conduitTheme.textPrimary,
fontWeight: FontWeight.bold,
fontSize: radius * 0.6,
),
),
memCacheWidth: (radius * 2).toInt(),
memCacheHeight: (radius * 2).toInt(),
),
)
: Text(
fallbackText.isNotEmpty ? fallbackText[0].toUpperCase() : '?',
style: TextStyle(
color: textColor ?? context.conduitTheme.textPrimary,
fontWeight: FontWeight.bold,
fontSize: radius * 0.6,
),
),
);
}
}

View File

@@ -1,448 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_animate/flutter_animate.dart';
import 'dart:io' show Platform;
import '../theme/theme_extensions.dart';
import '../services/brand_service.dart';
/// Enhanced empty state widgets with illustrations and actions
class ConduitEmptyState extends StatelessWidget {
final String title;
final String? subtitle;
final IconData? icon;
final Widget? illustration;
final List<EmptyStateAction>? actions;
final bool isLoading;
const ConduitEmptyState({
super.key,
required this.title,
this.subtitle,
this.icon,
this.illustration,
this.actions,
this.isLoading = false,
});
@override
Widget build(BuildContext context) {
final conduitTheme = context.conduitTheme;
return Center(
child: Padding(
padding: const EdgeInsets.all(Spacing.xl),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Illustration or icon
if (illustration != null)
illustration!
else if (icon != null)
Container(
width: IconSize.xxl * 2.5, // 120px equivalent
height: IconSize.xxl * 2.5, // 120px equivalent
decoration: BoxDecoration(
color: conduitTheme.cardBackground,
shape: BoxShape.circle,
border: Border.all(color: conduitTheme.cardBorder, width: 2),
),
child: Icon(
icon!,
size: IconSize.xxl,
color: context.conduitTheme.iconSecondary,
),
)
else
// Default to brand icon when no specific icon or illustration provided
BrandService.createBrandEmptyStateIcon(
size: IconSize.xxl * 2.5, // 120px equivalent
showBackground: true,
),
const SizedBox(height: Spacing.xl),
// Title
Text(
title,
style: conduitTheme.headingMedium,
textAlign: TextAlign.center,
),
// Subtitle
if (subtitle != null) ...[
const SizedBox(height: Spacing.xs),
Text(
subtitle!,
style: conduitTheme.bodyMedium?.copyWith(
color: context.conduitTheme.textSecondary,
),
textAlign: TextAlign.center,
),
],
// Actions
if (actions != null && actions!.isNotEmpty) ...[
const SizedBox(height: Spacing.xl),
...actions!.map(
(action) => Padding(
padding: const EdgeInsets.only(bottom: Spacing.xs),
child: _buildActionButton(context, action),
),
),
],
],
),
),
).animate().fadeIn(
duration: const Duration(milliseconds: 300),
curve: Curves.easeOut,
);
}
Widget _buildActionButton(BuildContext context, EmptyStateAction action) {
return SizedBox(
width: double.infinity,
child: FilledButton(
onPressed: action.onPressed,
style: action.isPrimary
? FilledButton.styleFrom(
backgroundColor: context.conduitTheme.buttonPrimary,
foregroundColor: context.conduitTheme.buttonPrimaryText,
)
: FilledButton.styleFrom(
backgroundColor: Colors.transparent,
foregroundColor: context.conduitTheme.textSecondary,
side: BorderSide(
color: context.conduitTheme.dividerColor,
width: 1,
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (action.icon != null) ...[
Icon(action.icon, size: IconSize.md),
const SizedBox(width: Spacing.sm),
],
Text(action.label),
],
),
),
);
}
}
/// Action for empty states
class EmptyStateAction {
final String label;
final VoidCallback onPressed;
final IconData? icon;
final bool isPrimary;
const EmptyStateAction({
required this.label,
required this.onPressed,
this.icon,
this.isPrimary = true,
});
}
/// Chat-specific empty state
class ChatEmptyState extends StatelessWidget {
final VoidCallback? onStartChat;
const ChatEmptyState({super.key, this.onStartChat});
@override
Widget build(BuildContext context) {
return ConduitEmptyState(
title: 'Start a conversation',
subtitle:
'Ask me anything! I\'m here to help with questions, creative tasks, analysis, and more.',
// Remove custom illustration to use default brand icon
icon: BrandService.primaryIcon,
actions: onStartChat != null
? [
EmptyStateAction(
label: 'Start chatting',
icon: BrandService.primaryIcon,
onPressed: onStartChat!,
),
]
: null,
);
}
}
/// Files empty state
class FilesEmptyState extends StatelessWidget {
final VoidCallback? onUploadFile;
const FilesEmptyState({super.key, this.onUploadFile});
@override
Widget build(BuildContext context) {
return ConduitEmptyState(
title: 'No files yet',
subtitle:
'Upload documents, images, or other files to get started with your knowledge base.',
illustration: Builder(
builder: (context) => _buildFilesIllustration(context),
),
actions: onUploadFile != null
? [
EmptyStateAction(
label: 'Upload files',
icon: Platform.isIOS
? CupertinoIcons.doc_on_doc
: Icons.upload_file,
onPressed: onUploadFile!,
),
]
: null,
);
}
Widget _buildFilesIllustration(BuildContext context) {
return SizedBox(
width: 120,
height: 120,
child: Stack(
alignment: Alignment.center,
children: [
// Background circle
Container(
width: IconSize.xxl * 2.5, // 120px equivalent
height: IconSize.xxl * 2.5, // 120px equivalent
decoration: BoxDecoration(
color: context.conduitTheme.info.withValues(alpha: 0.1),
shape: BoxShape.circle,
),
),
// File stack
...List.generate(3, (index) {
return Positioned(
top: 30 + (index * 8.0),
left: 30 + (index * 4.0),
child:
Container(
width: TouchTarget.minimum,
height: 50,
decoration: BoxDecoration(
color: [
context.conduitTheme.info,
context.conduitTheme.success,
context.conduitTheme.warning,
][index],
borderRadius: BorderRadius.circular(
AppBorderRadius.xs,
),
),
child: Icon(
[Icons.description, Icons.image, Icons.folder][index],
color: context.conduitTheme.textInverse,
size: IconSize.md,
),
)
.animate(delay: Duration(milliseconds: index * 200))
.fadeIn()
.slideY(begin: 0.3, end: 0),
);
}),
],
),
);
}
}
/// Tools empty state
class ToolsEmptyState extends StatelessWidget {
final VoidCallback? onExploreTools;
const ToolsEmptyState({super.key, this.onExploreTools});
@override
Widget build(BuildContext context) {
return ConduitEmptyState(
title: 'Powerful tools await',
subtitle: 'Discover tools to enhance your productivity and creativity.',
illustration: Builder(
builder: (context) => _buildToolsIllustration(context),
),
actions: onExploreTools != null
? [
EmptyStateAction(
label: 'Explore tools',
icon: Platform.isIOS
? CupertinoIcons.wand_stars
: Icons.auto_awesome,
onPressed: onExploreTools!,
),
]
: null,
);
}
Widget _buildToolsIllustration(BuildContext context) {
return SizedBox(
width: 120,
height: 120,
child: Stack(
alignment: Alignment.center,
children: [
// Background circle
Container(
width: IconSize.xxl * 2.5, // 120px equivalent
height: IconSize.xxl * 2.5, // 120px equivalent
decoration: BoxDecoration(
color: context.conduitTheme.buttonPrimary.withValues(alpha: 0.1),
shape: BoxShape.circle,
),
),
// Tools arrangement
...List.generate(6, (index) {
final angle = (index * 60) * (3.14159 / 180);
final radius = 35.0;
return Positioned(
top: 60 + (radius * -cos(angle)) - 15,
left: 60 + (radius * sin(angle)) - 15,
child:
Container(
width: Spacing.xl - Spacing.xxs, // 30px equivalent
height: Spacing.xl - Spacing.xxs, // 30px equivalent
decoration: BoxDecoration(
color: context.conduitTheme.buttonPrimary,
shape: BoxShape.circle,
),
child: Icon(
[
Icons.palette,
Icons.calculate,
Icons.code,
Icons.translate,
Icons.music_note,
Icons.analytics,
][index],
color: context.conduitTheme.textInverse,
size: IconSize.sm,
),
)
.animate(delay: Duration(milliseconds: index * 100))
.fadeIn()
.scale(
begin: const Offset(0.5, 0.5),
end: const Offset(1.0, 1.0),
),
);
}),
],
),
);
}
}
/// Search results empty state
class SearchEmptyState extends StatelessWidget {
final String query;
final VoidCallback? onClearSearch;
const SearchEmptyState({super.key, required this.query, this.onClearSearch});
@override
Widget build(BuildContext context) {
return ConduitEmptyState(
title: 'No results found',
subtitle: 'No results for "$query". Try adjusting your search terms.',
icon: Platform.isIOS ? CupertinoIcons.search : Icons.search_off,
actions: onClearSearch != null
? [
EmptyStateAction(
label: 'Clear search',
icon: Platform.isIOS ? CupertinoIcons.clear : Icons.clear,
onPressed: onClearSearch!,
isPrimary: false,
),
]
: null,
);
}
}
/// Connection error empty state
class ConnectionEmptyState extends StatelessWidget {
final VoidCallback? onRetry;
const ConnectionEmptyState({super.key, this.onRetry});
@override
Widget build(BuildContext context) {
return ConduitEmptyState(
title: 'Connection problem',
subtitle:
'Unable to load content. Please check your connection and try again.',
icon: Platform.isIOS ? CupertinoIcons.wifi_slash : Icons.wifi_off,
actions: onRetry != null
? [
EmptyStateAction(
label: 'Try again',
icon: Platform.isIOS ? CupertinoIcons.refresh : Icons.refresh,
onPressed: onRetry!,
),
]
: null,
);
}
}
/// Generic empty state with custom illustration
class CustomEmptyState extends StatelessWidget {
final String title;
final String subtitle;
final Widget illustration;
final List<EmptyStateAction>? actions;
const CustomEmptyState({
super.key,
required this.title,
required this.subtitle,
required this.illustration,
this.actions,
});
@override
Widget build(BuildContext context) {
return ConduitEmptyState(
title: title,
subtitle: subtitle,
illustration: illustration,
actions: actions,
);
}
}
// Helper function to get cosine
double cos(double radians) {
// Simple cosine approximation for illustration positioning
if (radians == 0) return 1.0;
if (radians == 1.5708) return 0.0; // π/2
if (radians == 3.14159) return -1.0; // π
if (radians == 4.71239) return 0.0; // 3π/2
// Taylor series approximation for other values
double x2 = radians * radians;
return 1 - x2 / 2 + x2 * x2 / 24 - x2 * x2 * x2 / 720;
}
// Helper function to get sine
double sin(double radians) {
// Simple sine approximation for illustration positioning
if (radians == 0) return 0.0;
if (radians == 1.5708) return 1.0; // π/2
if (radians == 3.14159) return 0.0; // π
if (radians == 4.71239) return -1.0; // 3π/2
// Taylor series approximation for other values
double x2 = radians * radians;
return radians - radians * x2 / 6 + radians * x2 * x2 / 120;
}

View File

@@ -1,397 +0,0 @@
import 'package:flutter/material.dart';
import '../theme/theme_extensions.dart';
import 'conduit_components.dart';
/// Enhanced error widget with production-grade design and better hierarchy
class ConduitErrorWidget extends StatelessWidget {
final String title;
final String message;
final String? actionLabel;
final VoidCallback? onAction;
final IconData? icon;
final bool isCompact;
const ConduitErrorWidget({
super.key,
required this.title,
required this.message,
this.actionLabel,
this.onAction,
this.icon,
this.isCompact = false,
});
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(isCompact ? Spacing.md : Spacing.cardPadding),
decoration: BoxDecoration(
color: context.conduitTheme.errorBackground.withValues(
alpha: Alpha.badgeBackground,
),
borderRadius: BorderRadius.circular(AppBorderRadius.card),
border: Border.all(
color: context.conduitTheme.error.withValues(alpha: Alpha.subtle),
width: BorderWidth.standard,
),
boxShadow: ConduitShadows.card,
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
icon ?? Icons.error_outline,
size: isCompact ? IconSize.large : IconSize.xl,
color: context.conduitTheme.error,
),
SizedBox(height: isCompact ? Spacing.sm : Spacing.md),
Text(
title,
style: AppTypography.headlineSmallStyle.copyWith(
color: context.conduitTheme.error,
fontWeight: FontWeight.w600,
),
textAlign: TextAlign.center,
),
SizedBox(height: isCompact ? Spacing.xs : Spacing.sm),
Text(
message,
style: AppTypography.standard.copyWith(
color: context.conduitTheme.textSecondary,
),
textAlign: TextAlign.center,
),
if (actionLabel != null && onAction != null) ...[
SizedBox(height: isCompact ? Spacing.md : Spacing.lg),
SizedBox(
width: double.infinity,
child: ConduitButton(
text: actionLabel!,
onPressed: onAction,
isDestructive: true,
isCompact: isCompact,
),
),
],
],
),
);
}
}
/// Enhanced network error widget with better hierarchy
class NetworkErrorWidget extends StatelessWidget {
final VoidCallback? onRetry;
final String? customMessage;
final bool isCompact;
const NetworkErrorWidget({
super.key,
this.onRetry,
this.customMessage,
this.isCompact = false,
});
@override
Widget build(BuildContext context) {
return ConduitErrorWidget(
title: 'Connection Error',
message:
customMessage ??
'Unable to connect to the server. Please check your internet connection and try again.',
actionLabel: 'Retry',
onAction: onRetry,
icon: Icons.wifi_off,
isCompact: isCompact,
);
}
}
/// Enhanced empty state widget with better hierarchy
class EmptyStateWidget extends StatelessWidget {
final String title;
final String message;
final IconData? icon;
final String? actionLabel;
final VoidCallback? onAction;
final bool isCompact;
const EmptyStateWidget({
super.key,
required this.title,
required this.message,
this.icon,
this.actionLabel,
this.onAction,
this.isCompact = false,
});
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(isCompact ? Spacing.md : Spacing.cardPadding),
decoration: BoxDecoration(
color: context.conduitTheme.cardBackground,
borderRadius: BorderRadius.circular(AppBorderRadius.card),
border: Border.all(
color: context.conduitTheme.cardBorder,
width: BorderWidth.standard,
),
boxShadow: ConduitShadows.card,
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
icon ?? Icons.inbox_outlined,
size: isCompact ? IconSize.large : IconSize.xxl,
color: context.conduitTheme.iconSecondary,
),
SizedBox(height: isCompact ? Spacing.sm : Spacing.md),
Text(
title,
style: AppTypography.headlineSmallStyle.copyWith(
color: context.conduitTheme.textPrimary,
fontWeight: FontWeight.w600,
),
textAlign: TextAlign.center,
),
SizedBox(height: isCompact ? Spacing.xs : Spacing.sm),
Text(
message,
style: AppTypography.standard.copyWith(
color: context.conduitTheme.textSecondary,
),
textAlign: TextAlign.center,
),
if (actionLabel != null && onAction != null) ...[
SizedBox(height: isCompact ? Spacing.md : Spacing.lg),
SizedBox(
width: double.infinity,
child: ConduitButton(
text: actionLabel!,
onPressed: onAction,
isCompact: isCompact,
),
),
],
],
),
);
}
}
/// Enhanced loading error widget with better hierarchy
class LoadingErrorWidget extends StatelessWidget {
final String message;
final VoidCallback? onRetry;
final bool isCompact;
const LoadingErrorWidget({
super.key,
required this.message,
this.onRetry,
this.isCompact = false,
});
@override
Widget build(BuildContext context) {
return ConduitErrorWidget(
title: 'Loading Failed',
message: message,
actionLabel: onRetry != null ? 'Try Again' : null,
onAction: onRetry,
icon: Icons.error_outline,
isCompact: isCompact,
);
}
}
/// Enhanced validation error widget with better hierarchy
class ValidationErrorWidget extends StatelessWidget {
final String fieldName;
final String message;
final VoidCallback? onFix;
final bool isCompact;
const ValidationErrorWidget({
super.key,
required this.fieldName,
required this.message,
this.onFix,
this.isCompact = false,
});
@override
Widget build(BuildContext context) {
return ConduitErrorWidget(
title: 'Invalid $fieldName',
message: message,
actionLabel: onFix != null ? 'Fix Now' : null,
onAction: onFix,
icon: Icons.warning_amber_outlined,
isCompact: isCompact,
);
}
}
/// Enhanced permission error widget with better hierarchy
class PermissionErrorWidget extends StatelessWidget {
final String permission;
final String message;
final VoidCallback? onGrant;
final bool isCompact;
const PermissionErrorWidget({
super.key,
required this.permission,
required this.message,
this.onGrant,
this.isCompact = false,
});
@override
Widget build(BuildContext context) {
return ConduitErrorWidget(
title: 'Permission Required',
message: 'This app needs $permission permission to $message.',
actionLabel: onGrant != null ? 'Grant Permission' : null,
onAction: onGrant,
icon: Icons.security,
isCompact: isCompact,
);
}
}
/// Enhanced server error widget with better hierarchy
class ServerErrorWidget extends StatelessWidget {
final String error;
final VoidCallback? onRetry;
final bool isCompact;
const ServerErrorWidget({
super.key,
required this.error,
this.onRetry,
this.isCompact = false,
});
@override
Widget build(BuildContext context) {
return ConduitErrorWidget(
title: 'Server Error',
message: error,
actionLabel: onRetry != null ? 'Retry' : null,
onAction: onRetry,
icon: Icons.cloud_off,
isCompact: isCompact,
);
}
}
/// Enhanced file error widget with better hierarchy
class FileErrorWidget extends StatelessWidget {
final String fileName;
final String error;
final VoidCallback? onRetry;
final bool isCompact;
const FileErrorWidget({
super.key,
required this.fileName,
required this.error,
this.onRetry,
this.isCompact = false,
});
@override
Widget build(BuildContext context) {
return ConduitErrorWidget(
title: 'File Error',
message: 'Failed to process $fileName: $error',
actionLabel: onRetry != null ? 'Try Again' : null,
onAction: onRetry,
icon: Icons.file_present,
isCompact: isCompact,
);
}
}
/// Enhanced authentication error widget with better hierarchy
class AuthErrorWidget extends StatelessWidget {
final String message;
final VoidCallback? onLogin;
final bool isCompact;
const AuthErrorWidget({
super.key,
required this.message,
this.onLogin,
this.isCompact = false,
});
@override
Widget build(BuildContext context) {
return ConduitErrorWidget(
title: 'Authentication Required',
message: message,
actionLabel: onLogin != null ? 'Sign In' : null,
onAction: onLogin,
icon: Icons.lock_outline,
isCompact: isCompact,
);
}
}
/// Enhanced offline error widget with better hierarchy
class OfflineErrorWidget extends StatelessWidget {
final String message;
final VoidCallback? onRetry;
final bool isCompact;
const OfflineErrorWidget({
super.key,
this.message =
'You\'re currently offline. Please check your internet connection.',
this.onRetry,
this.isCompact = false,
});
@override
Widget build(BuildContext context) {
return ConduitErrorWidget(
title: 'Offline',
message: message,
actionLabel: onRetry != null ? 'Retry' : null,
onAction: onRetry,
icon: Icons.wifi_off,
isCompact: isCompact,
);
}
}
/// Enhanced timeout error widget with better hierarchy
class TimeoutErrorWidget extends StatelessWidget {
final String operation;
final VoidCallback? onRetry;
final bool isCompact;
const TimeoutErrorWidget({
super.key,
required this.operation,
this.onRetry,
this.isCompact = false,
});
@override
Widget build(BuildContext context) {
return ConduitErrorWidget(
title: 'Request Timeout',
message: 'The $operation request timed out. Please try again.',
actionLabel: onRetry != null ? 'Retry' : null,
onAction: onRetry,
icon: Icons.timer_off,
isCompact: isCompact,
);
}
}