Quotation
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:pshared/models/payment/quote/status_type.dart';
|
||||
import 'package:pshared/models/auto_refresh_mode.dart';
|
||||
|
||||
import 'package:pweb/pages/dashboard/payouts/quote_status/widgets/refresh_section.dart';
|
||||
import 'package:pweb/pages/dashboard/payouts/quote_status/widgets/card.dart';
|
||||
|
||||
|
||||
class QuoteStatusBody extends StatelessWidget {
|
||||
final double spacing;
|
||||
final QuoteStatusType statusType;
|
||||
final String statusText;
|
||||
final String? helperText;
|
||||
final bool isLoading;
|
||||
final bool canRefresh;
|
||||
final bool showPrimaryRefresh;
|
||||
final AutoRefreshMode autoRefreshMode;
|
||||
final ValueChanged<AutoRefreshMode> onAutoRefreshModeChanged;
|
||||
final VoidCallback onRefresh;
|
||||
|
||||
const QuoteStatusBody({
|
||||
super.key,
|
||||
required this.spacing,
|
||||
required this.statusType,
|
||||
required this.statusText,
|
||||
required this.helperText,
|
||||
required this.isLoading,
|
||||
required this.canRefresh,
|
||||
required this.showPrimaryRefresh,
|
||||
required this.autoRefreshMode,
|
||||
required this.onAutoRefreshModeChanged,
|
||||
required this.onRefresh,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
QuoteStatusCard(
|
||||
statusType: statusType,
|
||||
isLoading: isLoading,
|
||||
statusText: statusText,
|
||||
helperText: helperText,
|
||||
canRefresh: canRefresh,
|
||||
showPrimaryRefresh: showPrimaryRefresh,
|
||||
onRefresh: onRefresh,
|
||||
),
|
||||
SizedBox(height: spacing),
|
||||
QuoteAutoRefreshSection(
|
||||
autoRefreshMode: autoRefreshMode,
|
||||
canRefresh: canRefresh,
|
||||
onModeChanged: onAutoRefreshModeChanged,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:pshared/models/payment/quote/status_type.dart';
|
||||
|
||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||
|
||||
|
||||
class QuoteStatusCard extends StatelessWidget {
|
||||
final QuoteStatusType statusType;
|
||||
final bool isLoading;
|
||||
final String statusText;
|
||||
final String? helperText;
|
||||
final bool canRefresh;
|
||||
final bool showPrimaryRefresh;
|
||||
final VoidCallback onRefresh;
|
||||
|
||||
const QuoteStatusCard({
|
||||
super.key,
|
||||
required this.statusType,
|
||||
required this.isLoading,
|
||||
required this.statusText,
|
||||
required this.helperText,
|
||||
required this.canRefresh,
|
||||
required this.showPrimaryRefresh,
|
||||
required this.onRefresh,
|
||||
});
|
||||
|
||||
static const double _cardRadius = 12;
|
||||
static const double _cardSpacing = 12;
|
||||
static const double _iconSize = 18;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final foregroundColor = _resolveForegroundColor(theme, statusType);
|
||||
final statusStyle = theme.textTheme.bodyMedium?.copyWith(color: foregroundColor);
|
||||
final helperStyle = theme.textTheme.bodySmall?.copyWith(
|
||||
color: foregroundColor.withValues(alpha: 0.8),
|
||||
);
|
||||
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(_cardSpacing),
|
||||
decoration: BoxDecoration(
|
||||
color: _resolveCardColor(theme, statusType),
|
||||
borderRadius: BorderRadius.circular(_cardRadius),
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 2),
|
||||
child: isLoading
|
||||
? SizedBox(
|
||||
width: _iconSize,
|
||||
height: _iconSize,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
valueColor: AlwaysStoppedAnimation<Color>(foregroundColor),
|
||||
),
|
||||
)
|
||||
: Icon(
|
||||
_resolveIcon(statusType),
|
||||
size: _iconSize,
|
||||
color: foregroundColor,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: _cardSpacing),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(statusText, style: statusStyle),
|
||||
if (helperText != null) ...[
|
||||
const SizedBox(height: 4),
|
||||
Text(helperText!, style: helperStyle),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
if (canRefresh)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: _cardSpacing),
|
||||
child: showPrimaryRefresh
|
||||
? ElevatedButton(
|
||||
onPressed: canRefresh ? onRefresh : null,
|
||||
child: Text(AppLocalizations.of(context)!.quoteRefresh),
|
||||
)
|
||||
: TextButton(
|
||||
onPressed: canRefresh ? onRefresh : null,
|
||||
child: Text(AppLocalizations.of(context)!.quoteRefresh),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Color _resolveCardColor(ThemeData theme, QuoteStatusType status) {
|
||||
switch (status) {
|
||||
case QuoteStatusType.loading:
|
||||
return theme.colorScheme.secondaryContainer;
|
||||
case QuoteStatusType.error:
|
||||
case QuoteStatusType.expired:
|
||||
return theme.colorScheme.errorContainer;
|
||||
case QuoteStatusType.active:
|
||||
return theme.colorScheme.primaryContainer;
|
||||
case QuoteStatusType.missing:
|
||||
return theme.colorScheme.surfaceContainerHighest;
|
||||
}
|
||||
}
|
||||
|
||||
Color _resolveForegroundColor(ThemeData theme, QuoteStatusType status) {
|
||||
switch (status) {
|
||||
case QuoteStatusType.loading:
|
||||
return theme.colorScheme.onSecondaryContainer;
|
||||
case QuoteStatusType.error:
|
||||
case QuoteStatusType.expired:
|
||||
return theme.colorScheme.onErrorContainer;
|
||||
case QuoteStatusType.active:
|
||||
return theme.colorScheme.onPrimaryContainer;
|
||||
case QuoteStatusType.missing:
|
||||
return theme.colorScheme.onSurfaceVariant;
|
||||
}
|
||||
}
|
||||
|
||||
IconData _resolveIcon(QuoteStatusType status) {
|
||||
switch (status) {
|
||||
case QuoteStatusType.loading:
|
||||
return Icons.sync_rounded;
|
||||
case QuoteStatusType.error:
|
||||
return Icons.warning_amber_rounded;
|
||||
case QuoteStatusType.expired:
|
||||
return Icons.error_outline_rounded;
|
||||
case QuoteStatusType.active:
|
||||
return Icons.timer_outlined;
|
||||
case QuoteStatusType.missing:
|
||||
return Icons.info_outline_rounded;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:pshared/models/auto_refresh_mode.dart';
|
||||
|
||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||
|
||||
|
||||
class QuoteAutoRefreshSection extends StatelessWidget {
|
||||
final AutoRefreshMode autoRefreshMode;
|
||||
final bool canRefresh;
|
||||
final ValueChanged<AutoRefreshMode> onModeChanged;
|
||||
|
||||
const QuoteAutoRefreshSection({
|
||||
super.key,
|
||||
required this.autoRefreshMode,
|
||||
required this.canRefresh,
|
||||
required this.onModeChanged,
|
||||
});
|
||||
|
||||
static const double _autoRefreshSpacing = 8;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final loc = AppLocalizations.of(context)!;
|
||||
final theme = Theme.of(context);
|
||||
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
autoRefreshMode == AutoRefreshMode.on
|
||||
? loc.quoteAutoRefreshEnabled
|
||||
: loc.quoteAutoRefreshDisabled,
|
||||
style: theme.textTheme.bodyMedium,
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
loc.quoteAutoRefreshHint,
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
color: theme.textTheme.bodySmall?.color?.withValues(alpha: 0.7),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: _autoRefreshSpacing),
|
||||
ToggleButtons(
|
||||
isSelected: [
|
||||
autoRefreshMode == AutoRefreshMode.off,
|
||||
autoRefreshMode == AutoRefreshMode.on,
|
||||
],
|
||||
onPressed: canRefresh
|
||||
? (index) {
|
||||
final nextMode =
|
||||
index == 1 ? AutoRefreshMode.on : AutoRefreshMode.off;
|
||||
if (nextMode == autoRefreshMode) return;
|
||||
onModeChanged(nextMode);
|
||||
}
|
||||
: null,
|
||||
borderRadius: BorderRadius.circular(999),
|
||||
constraints: const BoxConstraints(minHeight: 32, minWidth: 56),
|
||||
selectedColor: theme.colorScheme.onPrimary,
|
||||
fillColor: theme.colorScheme.primary,
|
||||
color: theme.colorScheme.onSurface,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
child: Text(loc.toggleOff),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
child: Text(loc.toggleOn),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user