feat: Refactor hub widgets to use design system styles

Replaced hardcoded colors, icons, and spacing in hub-related widgets with values from the design system (UiColors, UiTypography, UiIcons, UiConstants). This improves consistency and maintainability across the UI components.
This commit is contained in:
Achintha Isuru
2026-01-22 13:20:39 -05:00
parent d2770d2d29
commit cd0b591c5c
5 changed files with 117 additions and 174 deletions

View File

@@ -42,20 +42,17 @@ class _AddHubDialogState extends State<AddHubDialog> {
@override
Widget build(BuildContext context) {
return Container(
color: Colors.black.withValues(alpha: 0.5),
color: UiColors.bgOverlay,
child: Center(
child: SingleChildScrollView(
child: Container(
width: MediaQuery.of(context).size.width * 0.9,
padding: const EdgeInsets.all(24),
padding: const EdgeInsets.all(UiConstants.space5),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(24),
boxShadow: [
BoxShadow(
color: Colors.black.withValues(alpha: 0.1),
blurRadius: 20,
),
color: UiColors.bgPopup,
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
boxShadow: const [
BoxShadow(color: UiColors.popupShadow, blurRadius: 20),
],
),
child: Column(
@@ -64,29 +61,27 @@ class _AddHubDialogState extends State<AddHubDialog> {
children: [
Text(
t.client_hubs.add_hub_dialog.title,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Color(0xFF0F172A),
),
style: UiTypography.headline3m.textPrimary,
),
const SizedBox(height: 24),
const SizedBox(height: UiConstants.space5),
_buildFieldLabel(t.client_hubs.add_hub_dialog.name_label),
TextField(
controller: _nameController,
style: UiTypography.body1r.textPrimary,
decoration: _buildInputDecoration(
t.client_hubs.add_hub_dialog.name_hint,
),
),
const SizedBox(height: 16),
const SizedBox(height: UiConstants.space4),
_buildFieldLabel(t.client_hubs.add_hub_dialog.address_label),
TextField(
controller: _addressController,
style: UiTypography.body1r.textPrimary,
decoration: _buildInputDecoration(
t.client_hubs.add_hub_dialog.address_hint,
),
),
const SizedBox(height: 32),
const SizedBox(height: UiConstants.space8),
Row(
children: [
Expanded(
@@ -95,7 +90,7 @@ class _AddHubDialogState extends State<AddHubDialog> {
text: t.common.cancel,
),
),
const SizedBox(width: 12),
const SizedBox(width: UiConstants.space3),
Expanded(
child: UiButton.primary(
onPressed: () {
@@ -121,36 +116,32 @@ class _AddHubDialogState extends State<AddHubDialog> {
Widget _buildFieldLabel(String label) {
return Padding(
padding: const EdgeInsets.only(bottom: 6),
child: Text(
label,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Color(0xFF0F172A),
),
),
padding: const EdgeInsets.only(bottom: UiConstants.space2),
child: Text(label, style: UiTypography.body2m.textPrimary),
);
}
InputDecoration _buildInputDecoration(String hint) {
return InputDecoration(
hintText: hint,
hintStyle: const TextStyle(color: Color(0xFF94A3B8), fontSize: 14),
hintStyle: UiTypography.body2r.textPlaceholder,
filled: true,
fillColor: const Color(0xFFF8FAFC),
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
fillColor: UiColors.input,
contentPadding: const EdgeInsets.symmetric(
horizontal: UiConstants.space4,
vertical: 14,
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(color: Color(0xFFE2E8F0)),
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
borderSide: const BorderSide(color: UiColors.border),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(color: Color(0xFFE2E8F0)),
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
borderSide: const BorderSide(color: UiColors.border),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(color: Color(0xFF2563EB), width: 2),
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
borderSide: const BorderSide(color: UiColors.ring, width: 2),
),
);
}

View File

@@ -1,6 +1,6 @@
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
import 'package:krow_domain/krow_domain.dart';
import 'package:lucide_icons/lucide_icons.dart';
import 'package:core_localization/core_localization.dart';
/// A card displaying information about a single hub.
@@ -27,68 +27,56 @@ class HubCard extends StatelessWidget {
final bool hasNfc = hub.nfcTagId != null;
return Container(
margin: const EdgeInsets.only(bottom: 12),
margin: const EdgeInsets.only(bottom: UiConstants.space3),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
color: UiColors.white,
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
boxShadow: const [
BoxShadow(
color: Colors.black.withValues(alpha: 0.04),
color: UiColors.popupShadow,
blurRadius: 10,
offset: const Offset(0, 4),
offset: Offset(0, 4),
),
],
),
child: Padding(
padding: const EdgeInsets.all(16),
padding: const EdgeInsets.all(UiConstants.space4),
child: Row(
children: [
Container(
width: 52,
height: 52,
decoration: BoxDecoration(
color: const Color(0xFFEFF6FF), // blue-50
borderRadius: BorderRadius.circular(16),
color: UiColors.tagInProgress,
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
),
child: Icon(
hasNfc ? LucideIcons.checkCircle : LucideIcons.nfc,
color: hasNfc
? const Color(0xFF16A34A)
: const Color(0xFF94A3B8), // green-600 or slate-400
hasNfc ? UiIcons.success : UiIcons.nfc,
color: hasNfc ? UiColors.iconSuccess : UiColors.iconThird,
size: 24,
),
),
const SizedBox(width: 16),
const SizedBox(width: UiConstants.space4),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
hub.name,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
color: Color(0xFF0F172A),
),
),
Text(hub.name, style: UiTypography.body1b.textPrimary),
if (hub.address.isNotEmpty)
Padding(
padding: const EdgeInsets.only(top: 4),
padding: const EdgeInsets.only(top: UiConstants.space1),
child: Row(
children: [
const Icon(
LucideIcons.mapPin,
UiIcons.mapPin,
size: 12,
color: Color(0xFF94A3B8),
color: UiColors.iconThird,
),
const SizedBox(width: 4),
const SizedBox(width: UiConstants.space1),
Expanded(
child: Text(
hub.address,
style: const TextStyle(
color: Color(0xFF64748B),
fontSize: 12,
),
style: UiTypography.footnote1r.textSecondary,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
@@ -98,14 +86,12 @@ class HubCard extends StatelessWidget {
),
if (hasNfc)
Padding(
padding: const EdgeInsets.only(top: 4),
padding: const EdgeInsets.only(top: UiConstants.space1),
child: Text(
t.client_hubs.hub_card.tag_label(id: hub.nfcTagId!),
style: const TextStyle(
color: Color(0xFF16A34A),
fontSize: 12,
style: UiTypography.footnote1b.copyWith(
color: UiColors.textSuccess,
fontFamily: 'monospace',
fontWeight: FontWeight.bold,
),
),
),
@@ -117,20 +103,20 @@ class HubCard extends StatelessWidget {
IconButton(
onPressed: onNfcPressed,
icon: const Icon(
LucideIcons.nfc,
color: Color(0xFF2563EB),
UiIcons.nfc,
color: UiColors.primary,
size: 20,
),
padding: EdgeInsets.zero,
constraints: const BoxConstraints(),
splashRadius: 20,
),
const SizedBox(width: 8),
const SizedBox(width: UiConstants.space2),
IconButton(
onPressed: onDeletePressed,
icon: const Icon(
LucideIcons.trash2,
color: Color(0xFFDC2626),
UiIcons.delete,
color: UiColors.destructive,
size: 20,
),
padding: EdgeInsets.zero,

View File

@@ -1,6 +1,5 @@
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
import 'package:lucide_icons/lucide_icons.dart';
import 'package:core_localization/core_localization.dart';
/// Widget displayed when there are no hubs.
@@ -14,15 +13,15 @@ class HubEmptyState extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(32),
padding: const EdgeInsets.all(UiConstants.space8),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
color: UiColors.bgBanner,
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
boxShadow: const [
BoxShadow(
color: Colors.black.withValues(alpha: 0.04),
color: UiColors.popupShadow,
blurRadius: 10,
offset: const Offset(0, 4),
offset: Offset(0, 4),
),
],
),
@@ -32,35 +31,27 @@ class HubEmptyState extends StatelessWidget {
width: 64,
height: 64,
decoration: const BoxDecoration(
color: Color(0xFFF1F5F9), // slate-100
color: UiColors.secondary,
shape: BoxShape.circle,
),
child: const Icon(
LucideIcons.nfc,
size: 32,
color: Color(0xFF94A3B8),
),
child: const Icon(UiIcons.nfc, size: 32, color: UiColors.iconThird),
),
const SizedBox(height: 16),
const SizedBox(height: UiConstants.space4),
Text(
t.client_hubs.empty_state.title,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Color(0xFF0F172A),
),
style: UiTypography.title1m.textPrimary,
),
const SizedBox(height: 8),
const SizedBox(height: UiConstants.space2),
Text(
t.client_hubs.empty_state.description,
textAlign: TextAlign.center,
style: const TextStyle(color: Color(0xFF64748B), fontSize: 14),
style: UiTypography.body2r.textSecondary,
),
const SizedBox(height: 24),
const SizedBox(height: UiConstants.space5),
UiButton.primary(
onPressed: onAddPressed,
text: t.client_hubs.empty_state.button,
leadingIcon: LucideIcons.plus,
leadingIcon: UiIcons.add,
),
],
),

View File

@@ -1,5 +1,5 @@
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
import 'package:lucide_icons/lucide_icons.dart';
import 'package:core_localization/core_localization.dart';
/// A card with information about how hubs work.
@@ -10,34 +10,29 @@ class HubInfoCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(16),
padding: const EdgeInsets.all(UiConstants.space4),
decoration: BoxDecoration(
color: const Color(0xFFEFF6FF), // blue-50
borderRadius: BorderRadius.circular(16),
color: UiColors.tagInProgress,
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Icon(LucideIcons.nfc, size: 20, color: Color(0xFF2563EB)),
const SizedBox(width: 12),
const Icon(UiIcons.nfc, size: 20, color: UiColors.primary),
const SizedBox(width: UiConstants.space3),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
t.client_hubs.about_hubs.title,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14,
color: Color(0xFF0F172A),
),
style: UiTypography.body2b.textPrimary,
),
const SizedBox(height: 4),
const SizedBox(height: UiConstants.space1),
Text(
t.client_hubs.about_hubs.description,
style: const TextStyle(
color: Color(0xFF334155),
fontSize: 12,
style: UiTypography.footnote1r.copyWith(
color: UiColors.textSecondary,
height: 1.4,
),
),

View File

@@ -1,6 +1,5 @@
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
import 'package:lucide_icons/lucide_icons.dart';
import 'package:krow_domain/krow_domain.dart';
import 'package:core_localization/core_localization.dart';
@@ -40,20 +39,17 @@ class _IdentifyNfcDialogState extends State<IdentifyNfcDialog> {
@override
Widget build(BuildContext context) {
return Container(
color: Colors.black.withValues(alpha: 0.5),
color: UiColors.bgOverlay,
child: Center(
child: SingleChildScrollView(
child: Container(
width: MediaQuery.of(context).size.width * 0.9,
padding: const EdgeInsets.all(24),
padding: const EdgeInsets.all(UiConstants.space5),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(24),
boxShadow: [
BoxShadow(
color: Colors.black.withValues(alpha: 0.1),
blurRadius: 20,
),
color: UiColors.bgPopup,
borderRadius: BorderRadius.circular(UiConstants.radiusBase),
boxShadow: const [
BoxShadow(color: UiColors.popupShadow, blurRadius: 20),
],
),
child: Column(
@@ -61,57 +57,45 @@ class _IdentifyNfcDialogState extends State<IdentifyNfcDialog> {
children: [
Text(
t.client_hubs.nfc_dialog.title,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Color(0xFF0F172A),
),
style: UiTypography.headline3m.textPrimary,
),
const SizedBox(height: 32),
const SizedBox(height: UiConstants.space8),
Container(
width: 80,
height: 80,
decoration: const BoxDecoration(
color: Color(0xFFEFF6FF), // blue-50
color: UiColors.tagInProgress,
shape: BoxShape.circle,
),
child: const Icon(
LucideIcons.nfc,
UiIcons.nfc,
size: 40,
color: Color(0xFF2563EB),
color: UiColors.primary,
),
),
const SizedBox(height: 16),
Text(
widget.hub.name,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
color: Color(0xFF0F172A),
),
),
const SizedBox(height: 8),
const SizedBox(height: UiConstants.space4),
Text(widget.hub.name, style: UiTypography.body1b.textPrimary),
const SizedBox(height: UiConstants.space2),
Text(
t.client_hubs.nfc_dialog.instruction,
textAlign: TextAlign.center,
style: const TextStyle(
color: Color(0xFF64748B),
fontSize: 14,
),
style: UiTypography.body2m.textSecondary,
),
const SizedBox(height: 24),
const SizedBox(height: UiConstants.space5),
UiButton.secondary(
onPressed: _simulateNFCScan,
text: t.client_hubs.nfc_dialog.scan_button,
leadingIcon: LucideIcons.nfc,
leadingIcon: UiIcons.nfc,
),
if (_nfcTagId != null) ...[
const SizedBox(height: 24),
const SizedBox(height: UiConstants.space6),
Container(
padding: const EdgeInsets.all(16),
padding: const EdgeInsets.all(UiConstants.space4),
decoration: BoxDecoration(
color: const Color(0xFFF0FDF4), // green-50
borderRadius: BorderRadius.circular(16),
color: UiColors.tagSuccess,
borderRadius: BorderRadius.circular(
UiConstants.radiusBase,
),
),
child: Column(
children: [
@@ -119,39 +103,35 @@ class _IdentifyNfcDialogState extends State<IdentifyNfcDialog> {
mainAxisSize: MainAxisSize.min,
children: [
const Icon(
LucideIcons.checkCircle,
UiIcons.success,
size: 20,
color: Color(0xFF16A34A),
color: UiColors.textSuccess,
),
const SizedBox(width: 8),
const SizedBox(width: UiConstants.space2),
Text(
t.client_hubs.nfc_dialog.tag_identified,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14,
color: Color(0xFF0F172A),
),
style: UiTypography.body2b.textPrimary,
),
],
),
const SizedBox(height: 8),
const SizedBox(height: UiConstants.space2),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 8,
horizontal: UiConstants.space3,
vertical: UiConstants.space2,
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: const Color(0xFFDCE8E0)),
color: UiColors.white,
borderRadius: BorderRadius.circular(
UiConstants.radiusMdValue + 2,
),
border: Border.all(color: UiColors.border),
),
child: Text(
_nfcTagId!,
style: const TextStyle(
style: UiTypography.footnote1b.copyWith(
fontFamily: 'monospace',
fontWeight: FontWeight.bold,
fontSize: 12,
color: Color(0xFF334155),
color: UiColors.textPrimary,
),
),
),
@@ -159,7 +139,7 @@ class _IdentifyNfcDialogState extends State<IdentifyNfcDialog> {
),
),
],
const SizedBox(height: 32),
const SizedBox(height: UiConstants.space8),
Row(
children: [
Expanded(
@@ -168,7 +148,7 @@ class _IdentifyNfcDialogState extends State<IdentifyNfcDialog> {
text: t.common.cancel,
),
),
const SizedBox(width: 12),
const SizedBox(width: UiConstants.space3),
Expanded(
child: UiButton.primary(
onPressed: _nfcTagId != null