refactor: resolve all hardcoded color references to support dynamic branding colors from backend via Theme.of(context)
This commit is contained in:
parent
f092a77b0f
commit
370099930d
@ -153,6 +153,9 @@ class _BranchesScreenState extends State<BranchesScreen> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final theme = Theme.of(context);
|
||||||
|
final colorScheme = theme.colorScheme;
|
||||||
|
|
||||||
return _isLoading
|
return _isLoading
|
||||||
? const Center(child: CircularProgressIndicator())
|
? const Center(child: CircularProgressIndicator())
|
||||||
: RefreshIndicator(
|
: RefreshIndicator(
|
||||||
@ -163,17 +166,17 @@ class _BranchesScreenState extends State<BranchesScreen> {
|
|||||||
if (_locationDenied)
|
if (_locationDenied)
|
||||||
Container(
|
Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
color: AppTheme.surfaceContainerLow,
|
color: colorScheme.surfaceContainerLow,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.location_off, size: 16, color: AppTheme.onSurfaceVariant),
|
Icon(Icons.location_off, size: 16, color: colorScheme.onSurfaceVariant),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
'Location not available. Showing branches alphabetically.',
|
'Location not available. Showing branches alphabetically.',
|
||||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
style: theme.textTheme.bodySmall?.copyWith(
|
||||||
color: AppTheme.onSurfaceVariant,
|
color: colorScheme.onSurfaceVariant,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -183,16 +186,16 @@ class _BranchesScreenState extends State<BranchesScreen> {
|
|||||||
else if (_userPosition != null)
|
else if (_userPosition != null)
|
||||||
Container(
|
Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
color: AppTheme.surfaceContainerLow,
|
color: colorScheme.surfaceContainerLow,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.my_location, size: 16, color: AppTheme.secondary),
|
Icon(Icons.my_location, size: 16, color: colorScheme.secondary),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Text(
|
Text(
|
||||||
'Sorted by distance from your location',
|
'Sorted by distance from your location',
|
||||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
style: theme.textTheme.bodySmall?.copyWith(
|
||||||
color: AppTheme.onSurfaceVariant,
|
color: colorScheme.onSurfaceVariant,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -234,7 +237,7 @@ class _BranchesScreenState extends State<BranchesScreen> {
|
|||||||
return Container(
|
return Container(
|
||||||
margin: const EdgeInsets.only(bottom: 12),
|
margin: const EdgeInsets.only(bottom: 12),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: AppTheme.surfaceContainerLow,
|
color: colorScheme.surfaceContainerLow,
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius: BorderRadius.circular(16),
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
@ -251,18 +254,18 @@ class _BranchesScreenState extends State<BranchesScreen> {
|
|||||||
leading: Container(
|
leading: Container(
|
||||||
padding: const EdgeInsets.all(12),
|
padding: const EdgeInsets.all(12),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: AppTheme.secondaryContainer,
|
color: colorScheme.secondaryContainer,
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
child: const Icon(Icons.storefront,
|
child: Icon(Icons.storefront,
|
||||||
color: AppTheme.secondary),
|
color: colorScheme.secondary),
|
||||||
),
|
),
|
||||||
title: Row(
|
title: Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
branch['name'] ?? 'Mapan Branch',
|
branch['name'] ?? 'Mapan Branch',
|
||||||
style: Theme.of(context)
|
style: theme
|
||||||
.textTheme
|
.textTheme
|
||||||
.titleMedium
|
.titleMedium
|
||||||
?.copyWith(
|
?.copyWith(
|
||||||
@ -277,16 +280,16 @@ class _BranchesScreenState extends State<BranchesScreen> {
|
|||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: 8, vertical: 3),
|
horizontal: 8, vertical: 3),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: AppTheme.secondaryContainer,
|
color: colorScheme.secondaryContainer,
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
distanceLabel,
|
distanceLabel,
|
||||||
style: Theme.of(context)
|
style: theme
|
||||||
.textTheme
|
.textTheme
|
||||||
.labelLarge
|
.labelLarge
|
||||||
?.copyWith(
|
?.copyWith(
|
||||||
color: AppTheme.onSecondaryContainer,
|
color: colorScheme.onSecondaryContainer,
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
@ -303,22 +306,22 @@ class _BranchesScreenState extends State<BranchesScreen> {
|
|||||||
addressParts.isEmpty
|
addressParts.isEmpty
|
||||||
? 'No address specified'
|
? 'No address specified'
|
||||||
: addressParts,
|
: addressParts,
|
||||||
style: Theme.of(context).textTheme.bodyMedium,
|
style: theme.textTheme.bodyMedium,
|
||||||
),
|
),
|
||||||
if (phone.isNotEmpty) ...[
|
if (phone.isNotEmpty) ...[
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.phone,
|
Icon(Icons.phone,
|
||||||
size: 14,
|
size: 14,
|
||||||
color: AppTheme.onSurfaceVariant),
|
color: colorScheme.onSurfaceVariant),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
Text(phone,
|
Text(phone,
|
||||||
style: Theme.of(context)
|
style: theme
|
||||||
.textTheme
|
.textTheme
|
||||||
.bodySmall
|
.bodySmall
|
||||||
?.copyWith(
|
?.copyWith(
|
||||||
color: AppTheme.onSurfaceVariant)),
|
color: colorScheme.onSurfaceVariant)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
@ -327,13 +330,13 @@ class _BranchesScreenState extends State<BranchesScreen> {
|
|||||||
),
|
),
|
||||||
trailing: phone.isNotEmpty
|
trailing: phone.isNotEmpty
|
||||||
? IconButton(
|
? IconButton(
|
||||||
icon: const Icon(Icons.chat_bubble,
|
icon: Icon(Icons.chat_bubble,
|
||||||
color: AppTheme.onSurface),
|
color: colorScheme.onSurface),
|
||||||
onPressed: () => _launchWhatsApp(phone),
|
onPressed: () => _launchWhatsApp(phone),
|
||||||
tooltip: 'Chat on WhatsApp',
|
tooltip: 'Chat on WhatsApp',
|
||||||
)
|
)
|
||||||
: const Icon(Icons.chevron_right,
|
: Icon(Icons.chevron_right,
|
||||||
color: AppTheme.onSurfaceVariant),
|
color: colorScheme.onSurfaceVariant),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import '../services/odoo_service.dart';
|
import '../services/odoo_service.dart';
|
||||||
import '../theme/app_theme.dart';
|
|
||||||
import '../widgets/carousel_widget.dart';
|
import '../widgets/carousel_widget.dart';
|
||||||
import '../widgets/promo_card_widget.dart';
|
import '../widgets/promo_card_widget.dart';
|
||||||
import '../widgets/subscription_list_widget.dart';
|
import '../widgets/subscription_list_widget.dart';
|
||||||
@ -130,20 +129,25 @@ class _LoyaltyCardTile extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final theme = Theme.of(context);
|
||||||
|
final colorScheme = theme.colorScheme;
|
||||||
final programName = (card['program_id']?[1] as String? ?? '').toLowerCase();
|
final programName = (card['program_id']?[1] as String? ?? '').toLowerCase();
|
||||||
String tier = 'MEMBER';
|
String tier = 'MEMBER';
|
||||||
if (programName.contains('silver')) tier = 'SILVER MEMBER';
|
if (programName.contains('silver')) tier = 'SILVER MEMBER';
|
||||||
if (programName.contains('gold')) tier = 'GOLD MEMBER';
|
if (programName.contains('gold')) tier = 'GOLD MEMBER';
|
||||||
if (programName.contains('platinum')) tier = 'PLATINUM MEMBER';
|
if (programName.contains('platinum')) tier = 'PLATINUM MEMBER';
|
||||||
|
|
||||||
|
final onPrimary = colorScheme.onPrimary;
|
||||||
|
final accentColor = colorScheme.secondary;
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
margin: const EdgeInsets.fromLTRB(16, 16, 16, 8),
|
margin: const EdgeInsets.fromLTRB(16, 16, 16, 8),
|
||||||
padding: const EdgeInsets.all(24),
|
padding: const EdgeInsets.all(24),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: AppTheme.primary, // Rich brick red background
|
color: colorScheme.primary,
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius: BorderRadius.circular(16),
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: const Color(0xFFF3DCA2), // Golden border
|
color: accentColor.withValues(alpha: 0.5),
|
||||||
width: 1.5,
|
width: 1.5,
|
||||||
),
|
),
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
@ -163,8 +167,8 @@ class _LoyaltyCardTile extends StatelessWidget {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
'${card['program_id']?[1] ?? 'Loyalty Program'}',
|
'${card['program_id']?[1] ?? 'Loyalty Program'}',
|
||||||
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
style: theme.textTheme.titleLarge?.copyWith(
|
||||||
color: Colors.white,
|
color: onPrimary,
|
||||||
fontFamily: 'serif',
|
fontFamily: 'serif',
|
||||||
),
|
),
|
||||||
softWrap: true,
|
softWrap: true,
|
||||||
@ -174,13 +178,13 @@ class _LoyaltyCardTile extends StatelessWidget {
|
|||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: const Color(0xFFB58428), // Golden honey badge background
|
color: accentColor,
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
tier,
|
tier,
|
||||||
style: Theme.of(context).textTheme.labelLarge?.copyWith(
|
style: theme.textTheme.labelLarge?.copyWith(
|
||||||
color: Colors.white,
|
color: colorScheme.primary.computeLuminance() > 0.5 ? Colors.black : Colors.white,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 9,
|
fontSize: 9,
|
||||||
letterSpacing: 0.8,
|
letterSpacing: 0.8,
|
||||||
@ -192,8 +196,8 @@ class _LoyaltyCardTile extends StatelessWidget {
|
|||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
Text(
|
Text(
|
||||||
'MEMBERSHIP CODE',
|
'MEMBERSHIP CODE',
|
||||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
style: theme.textTheme.bodySmall?.copyWith(
|
||||||
color: Colors.white.withValues(alpha: 0.7),
|
color: onPrimary.withValues(alpha: 0.7),
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
letterSpacing: 1.0,
|
letterSpacing: 1.0,
|
||||||
@ -202,8 +206,8 @@ class _LoyaltyCardTile extends StatelessWidget {
|
|||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
Text(
|
Text(
|
||||||
'${card['code'] ?? 'N/A'}',
|
'${card['code'] ?? 'N/A'}',
|
||||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
style: theme.textTheme.titleMedium?.copyWith(
|
||||||
color: Colors.white,
|
color: onPrimary,
|
||||||
fontFamily: 'monospace',
|
fontFamily: 'monospace',
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
@ -219,8 +223,8 @@ class _LoyaltyCardTile extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'AVAILABLE POINTS',
|
'AVAILABLE POINTS',
|
||||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
style: theme.textTheme.bodySmall?.copyWith(
|
||||||
color: Colors.white.withValues(alpha: 0.7),
|
color: onPrimary.withValues(alpha: 0.7),
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
letterSpacing: 1.0,
|
letterSpacing: 1.0,
|
||||||
@ -229,16 +233,16 @@ class _LoyaltyCardTile extends StatelessWidget {
|
|||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
const Icon(
|
Icon(
|
||||||
Icons.restaurant_rounded,
|
Icons.restaurant_rounded,
|
||||||
color: Color(0xFFF3DCA2),
|
color: accentColor,
|
||||||
size: 16,
|
size: 16,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 6),
|
const SizedBox(width: 6),
|
||||||
Text(
|
Text(
|
||||||
'Dine & Save',
|
'Dine & Save',
|
||||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
style: theme.textTheme.bodyMedium?.copyWith(
|
||||||
color: Colors.white.withValues(alpha: 0.9),
|
color: onPrimary.withValues(alpha: 0.9),
|
||||||
fontStyle: FontStyle.italic,
|
fontStyle: FontStyle.italic,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -248,8 +252,8 @@ class _LoyaltyCardTile extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'${card['points'] ?? 0}',
|
'${card['points'] ?? 0}',
|
||||||
style: Theme.of(context).textTheme.displayLarge?.copyWith(
|
style: theme.textTheme.displayLarge?.copyWith(
|
||||||
color: const Color(0xFFF3DCA2), // Bright golden amber accent
|
color: accentColor,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -5,7 +5,6 @@ import 'package:shared_preferences/shared_preferences.dart';
|
|||||||
import '../services/odoo_service.dart';
|
import '../services/odoo_service.dart';
|
||||||
import '../services/notification_service.dart';
|
import '../services/notification_service.dart';
|
||||||
import '../services/theme_manager.dart';
|
import '../services/theme_manager.dart';
|
||||||
import '../theme/app_theme.dart';
|
|
||||||
import 'notifications_screen.dart';
|
import 'notifications_screen.dart';
|
||||||
import 'loyalty_dashboard.dart';
|
import 'loyalty_dashboard.dart';
|
||||||
import 'branches_screen.dart';
|
import 'branches_screen.dart';
|
||||||
@ -195,7 +194,7 @@ class _MainShellState extends State<MainShell> {
|
|||||||
onDestinationSelected: (index) {
|
onDestinationSelected: (index) {
|
||||||
setState(() => _currentIndex = index);
|
setState(() => _currentIndex = index);
|
||||||
},
|
},
|
||||||
backgroundColor: AppTheme.surfaceContainerLowest,
|
backgroundColor: colorScheme.surfaceContainerLowest,
|
||||||
indicatorColor: colorScheme.primary,
|
indicatorColor: colorScheme.primary,
|
||||||
destinations: List.generate(4, (i) {
|
destinations: List.generate(4, (i) {
|
||||||
return NavigationDestination(
|
return NavigationDestination(
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import 'dart:convert';
|
|||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:smooth_page_indicator/smooth_page_indicator.dart';
|
import 'package:smooth_page_indicator/smooth_page_indicator.dart';
|
||||||
import '../theme/app_theme.dart';
|
|
||||||
import '../screens/carousel_detail_screen.dart';
|
import '../screens/carousel_detail_screen.dart';
|
||||||
|
|
||||||
/// Auto-scrolling carousel widget that shows slides from CMS.
|
/// Auto-scrolling carousel widget that shows slides from CMS.
|
||||||
@ -55,6 +54,8 @@ class _CarouselWidgetState extends State<CarouselWidget> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (widget.slides.isEmpty) return const SizedBox.shrink();
|
if (widget.slides.isEmpty) return const SizedBox.shrink();
|
||||||
|
final theme = Theme.of(context);
|
||||||
|
final colorScheme = theme.colorScheme;
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
@ -83,8 +84,8 @@ class _CarouselWidgetState extends State<CarouselWidget> {
|
|||||||
dotHeight: 6,
|
dotHeight: 6,
|
||||||
dotWidth: 6,
|
dotWidth: 6,
|
||||||
expansionFactor: 3,
|
expansionFactor: 3,
|
||||||
dotColor: AppTheme.surfaceContainer,
|
dotColor: colorScheme.surfaceContainer,
|
||||||
activeDotColor: AppTheme.secondary,
|
activeDotColor: colorScheme.secondary,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -99,6 +100,8 @@ class _SlideImage extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final theme = Theme.of(context);
|
||||||
|
final colorScheme = theme.colorScheme;
|
||||||
final base64Img = slide['image'] as String?;
|
final base64Img = slide['image'] as String?;
|
||||||
final externalUrl = slide['image_url'] as String?;
|
final externalUrl = slide['image_url'] as String?;
|
||||||
|
|
||||||
@ -110,7 +113,7 @@ class _SlideImage extends StatelessWidget {
|
|||||||
final Uint8List bytes = base64Decode(base64Img);
|
final Uint8List bytes = base64Decode(base64Img);
|
||||||
image = Image.memory(bytes, fit: BoxFit.cover, width: double.infinity);
|
image = Image.memory(bytes, fit: BoxFit.cover, width: double.infinity);
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
image = _placeholder();
|
image = _placeholder(colorScheme);
|
||||||
}
|
}
|
||||||
} else if (externalUrl != null && externalUrl.isNotEmpty) {
|
} else if (externalUrl != null && externalUrl.isNotEmpty) {
|
||||||
// External URL image
|
// External URL image
|
||||||
@ -118,20 +121,20 @@ class _SlideImage extends StatelessWidget {
|
|||||||
externalUrl,
|
externalUrl,
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
errorBuilder: (_, __, ___) => _placeholder(),
|
errorBuilder: (_, __, ___) => _placeholder(colorScheme),
|
||||||
loadingBuilder: (ctx, child, progress) {
|
loadingBuilder: (ctx, child, progress) {
|
||||||
if (progress == null) return child;
|
if (progress == null) return child;
|
||||||
return const Center(child: CircularProgressIndicator());
|
return const Center(child: CircularProgressIndicator());
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
image = _placeholder();
|
image = _placeholder(colorScheme);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: AppTheme.surfaceContainerLow,
|
color: colorScheme.surfaceContainerLow,
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius: BorderRadius.circular(16),
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
@ -148,11 +151,11 @@ class _SlideImage extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _placeholder() {
|
Widget _placeholder(ColorScheme colorScheme) {
|
||||||
return Container(
|
return Container(
|
||||||
color: AppTheme.surfaceContainer,
|
color: colorScheme.surfaceContainer,
|
||||||
child: const Center(
|
child: Center(
|
||||||
child: Icon(Icons.image_rounded, size: 48, color: AppTheme.outlineVariant),
|
child: Icon(Icons.image_rounded, size: 48, color: colorScheme.outline),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import '../theme/app_theme.dart';
|
|
||||||
import '../screens/promo_detail_screen.dart';
|
import '../screens/promo_detail_screen.dart';
|
||||||
|
|
||||||
/// Horizontal scrollable row of promo highlight cards.
|
/// Horizontal scrollable row of promo highlight cards.
|
||||||
@ -48,6 +47,8 @@ class _PromoCard extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final theme = Theme.of(context);
|
||||||
|
final colorScheme = theme.colorScheme;
|
||||||
final base64Img = promo['image_128'] as String?;
|
final base64Img = promo['image_128'] as String?;
|
||||||
final title = promo['name'] as String? ?? '';
|
final title = promo['name'] as String? ?? '';
|
||||||
|
|
||||||
@ -58,10 +59,10 @@ class _PromoCard extends StatelessWidget {
|
|||||||
imageWidget = Image.memory(bytes, fit: BoxFit.cover,
|
imageWidget = Image.memory(bytes, fit: BoxFit.cover,
|
||||||
width: double.infinity, height: 110);
|
width: double.infinity, height: 110);
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
imageWidget = _imagePlaceholder();
|
imageWidget = _imagePlaceholder(colorScheme);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
imageWidget = _imagePlaceholder();
|
imageWidget = _imagePlaceholder(colorScheme);
|
||||||
}
|
}
|
||||||
|
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
@ -75,10 +76,10 @@ class _PromoCard extends StatelessWidget {
|
|||||||
width: 140,
|
width: 140,
|
||||||
margin: const EdgeInsets.only(right: 12, bottom: 6),
|
margin: const EdgeInsets.only(right: 12, bottom: 6),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: AppTheme.surfaceContainerLowest,
|
color: colorScheme.surfaceContainerLowest,
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius: BorderRadius.circular(16),
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: AppTheme.outlineVariant.withValues(alpha: 0.3),
|
color: colorScheme.outline.withValues(alpha: 0.3),
|
||||||
width: 1,
|
width: 1,
|
||||||
),
|
),
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
@ -104,8 +105,8 @@ class _PromoCard extends StatelessWidget {
|
|||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
title,
|
title,
|
||||||
style: Theme.of(context).textTheme.labelLarge?.copyWith(
|
style: theme.textTheme.labelLarge?.copyWith(
|
||||||
color: AppTheme.onSurface,
|
color: colorScheme.onSurface,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 11,
|
fontSize: 11,
|
||||||
),
|
),
|
||||||
@ -119,11 +120,11 @@ class _PromoCard extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _imagePlaceholder() {
|
Widget _imagePlaceholder(ColorScheme colorScheme) {
|
||||||
return Container(
|
return Container(
|
||||||
color: AppTheme.surfaceContainer,
|
color: colorScheme.surfaceContainer,
|
||||||
child: const Center(
|
child: Center(
|
||||||
child: Icon(Icons.local_offer_rounded, size: 32, color: AppTheme.outlineVariant),
|
child: Icon(Icons.local_offer_rounded, size: 32, color: colorScheme.outline),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -74,6 +74,9 @@ class _SubscriptionCard extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final theme = Theme.of(context);
|
||||||
|
final colorScheme = theme.colorScheme;
|
||||||
|
|
||||||
final programName = sub['program_id'] is List
|
final programName = sub['program_id'] is List
|
||||||
? (sub['program_id'][1] as String? ?? 'Subscription')
|
? (sub['program_id'][1] as String? ?? 'Subscription')
|
||||||
: 'Subscription';
|
: 'Subscription';
|
||||||
@ -86,9 +89,9 @@ class _SubscriptionCard extends StatelessWidget {
|
|||||||
margin: const EdgeInsets.fromLTRB(16, 8, 16, 8),
|
margin: const EdgeInsets.fromLTRB(16, 8, 16, 8),
|
||||||
padding: const EdgeInsets.all(20),
|
padding: const EdgeInsets.all(20),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: AppTheme.surfaceContainerLowest,
|
color: colorScheme.surfaceContainerLowest,
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: active ? AppTheme.secondary.withValues(alpha: 0.4) : AppTheme.outlineVariant.withValues(alpha: 0.4),
|
color: active ? colorScheme.secondary.withValues(alpha: 0.4) : colorScheme.outline.withValues(alpha: 0.4),
|
||||||
width: 1.5,
|
width: 1.5,
|
||||||
),
|
),
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius: BorderRadius.circular(16),
|
||||||
@ -111,13 +114,13 @@ class _SubscriptionCard extends StatelessWidget {
|
|||||||
Icon(
|
Icon(
|
||||||
Icons.card_membership_rounded,
|
Icons.card_membership_rounded,
|
||||||
size: 18,
|
size: 18,
|
||||||
color: active ? AppTheme.secondary : AppTheme.outlineVariant,
|
color: active ? colorScheme.secondary : colorScheme.outline,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Text(
|
Text(
|
||||||
'SUBSCRIPTION CARD',
|
'SUBSCRIPTION CARD',
|
||||||
style: Theme.of(context).textTheme.labelLarge?.copyWith(
|
style: theme.textTheme.labelLarge?.copyWith(
|
||||||
color: active ? AppTheme.secondary : AppTheme.outlineVariant,
|
color: active ? colorScheme.secondary : colorScheme.outline,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
letterSpacing: 1.0,
|
letterSpacing: 1.0,
|
||||||
@ -150,9 +153,9 @@ class _SubscriptionCard extends StatelessWidget {
|
|||||||
const SizedBox(height: 14),
|
const SizedBox(height: 14),
|
||||||
Text(
|
Text(
|
||||||
programName,
|
programName,
|
||||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
style: theme.textTheme.titleMedium?.copyWith(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: AppTheme.onSurface,
|
color: colorScheme.onSurface,
|
||||||
fontFamily: 'serif',
|
fontFamily: 'serif',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -165,18 +168,18 @@ class _SubscriptionCard extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Card Number',
|
'Card Number',
|
||||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
style: theme.textTheme.bodySmall?.copyWith(
|
||||||
color: AppTheme.onSurfaceVariant,
|
color: colorScheme.onSurfaceVariant,
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 2),
|
const SizedBox(height: 2),
|
||||||
Text(
|
Text(
|
||||||
code.isNotEmpty ? code : 'N/A',
|
code.isNotEmpty ? code : 'N/A',
|
||||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
style: theme.textTheme.bodyMedium?.copyWith(
|
||||||
fontFamily: 'monospace',
|
fontFamily: 'monospace',
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: AppTheme.onSurface,
|
color: colorScheme.onSurface,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -186,16 +189,16 @@ class _SubscriptionCard extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Validity Period',
|
'Validity Period',
|
||||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
style: theme.textTheme.bodySmall?.copyWith(
|
||||||
color: AppTheme.onSurfaceVariant,
|
color: colorScheme.onSurfaceVariant,
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 2),
|
const SizedBox(height: 2),
|
||||||
Text(
|
Text(
|
||||||
'$startDate - $endDate',
|
'$startDate - $endDate',
|
||||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
style: theme.textTheme.bodyMedium?.copyWith(
|
||||||
color: AppTheme.onSurface,
|
color: colorScheme.onSurface,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user