kz_educa/lib/screens/dashboard_screen.dart

858 lines
32 KiB
Dart
Executable File

// lib/screens/dashboard_screen.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:intl/intl.dart';
import 'package:flutter/painting.dart';
import 'dart:ui';
import 'dart:math' as math;
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; // ✅ Importação do Font Awesome
import 'package:kzeduca_app/services/i18n_service.dart';
import 'package:kzeduca_app/screens/add_transaction_screen.dart';
import 'package:kzeduca_app/screens/savings_simulator_screen.dart';
import 'package:kzeduca_app/screens/lessons_screen.dart';
import 'package:kzeduca_app/screens/settings_screen.dart';
import 'package:kzeduca_app/screens/budget_screen.dart';
import 'package:kzeduca_app/screens/statistics_screen.dart';
import 'package:kzeduca_app/screens/challenges_screen.dart';
import 'package:kzeduca_app/screens/quiz_screen.dart';
import 'package:kzeduca_app/screens/receive_history_screen.dart';
import 'package:kzeduca_app/screens/notification_settings_screen.dart';
import 'package:kzeduca_app/screens/user_profile_screen.dart';
import 'package:kzeduca_app/services/user_state_service.dart';
import 'package:kzeduca_app/models/app_models.dart' as app_models;
import 'package:kzeduca_app/models/transaction.dart';
import 'package:kzeduca_app/services/hive_service.dart';
import 'package:kzeduca_app/services/transaction_list_notifier.dart';
import 'package:firebase_auth/firebase_auth.dart';
class DashboardScreen extends StatefulWidget {
const DashboardScreen({super.key});
@override
State<DashboardScreen> createState() => _DashboardScreenState();
}
class _DashboardScreenState extends State<DashboardScreen> {
int _selectedIndex = 0;
@override
void initState() {
super.initState();
}
void _handleCurrencyChange(String newCurrency) {
print("Moeda alterada para: $newCurrency");
}
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
// ✅ _buildNavItem modificado para aceitar IconData ou FaIcon
Widget _buildNavItem(int index, dynamic icon, String label) {
bool isSelected = _selectedIndex == index;
return Material(
color: Colors.transparent,
child: InkWell(
onTap: () => _onItemTapped(index),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0, horizontal: 2.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
padding: const EdgeInsets.all(6.0),
decoration: isSelected
? BoxDecoration(
shape: BoxShape.circle,
gradient: const LinearGradient(
colors: [Color(0xFF8A2BE2), Color(0xFFDA70D6)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
boxShadow: [
BoxShadow(
color: const Color(0xFFDA70D6).withOpacity(0.5),
spreadRadius: 1,
blurRadius: 5,
offset: const Offset(0, 3),
),
],
)
: null,
child: icon is IconData
? Icon(
icon,
color: isSelected ? Colors.white : Colors.white70,
size: 22,
)
: icon, // ✅ Aceita o widget FaIcon diretamente
),
const SizedBox(height: 2),
Text(
label,
style: TextStyle(
color: isSelected ? Colors.white : Colors.white70,
fontSize: 8,
),
),
],
),
),
),
);
}
@override
Widget build(BuildContext context) {
final i18n = Provider.of<I18nService>(context);
final List<Widget> widgetOptions = <Widget>[
const _DashboardMainContent(),
const BudgetScreen(),
const StatisticsScreen(),
const UserProfileScreen(),
];
return Scaffold(
backgroundColor: const Color(0xFF1E1C3A),
appBar: PreferredSize(
preferredSize: const Size.fromHeight(kToolbarHeight),
child: Container(
decoration: BoxDecoration(
gradient: const LinearGradient(
colors: [Color(0xFF1E1C3A), Color(0xFF1E1C3A)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.2),
spreadRadius: 2,
blurRadius: 8,
offset: const Offset(0, 4),
),
],
),
child: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
leading: Builder(
builder: (context) => IconButton(
icon: const Icon(Icons.menu, color: Colors.white),
onPressed: () {
Scaffold.of(context).openDrawer();
},
),
),
actions: [
IconButton(
// ✅ Ícone Font Awesome para Idioma
icon: const Icon(FontAwesomeIcons.globe, color: Colors.white, size: 20),
tooltip: i18n.t('change_language'),
onPressed: () {
final i18nService = Provider.of<I18nService>(context, listen: false);
final nextLocale = i18nService.locale.languageCode == 'pt' ? const Locale('en') : const Locale('pt');
i18nService.setLocale(nextLocale);
},
),
IconButton(
// ✅ Ícone Font Awesome para Notificações
icon: const Icon(FontAwesomeIcons.bell, color: Colors.white, size: 20),
tooltip: i18n.t('notifications'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (_) => const NotificationSettingsScreen()),
);
},
),
IconButton(
// ✅ Ícone Font Awesome para Perfil
icon: const Icon(FontAwesomeIcons.solidUser, color: Colors.white, size: 20),
tooltip: i18n.t('profile'),
onPressed: () {
setState(() {
_selectedIndex = 3;
});
},
),
],
),
),
),
drawer: Drawer(
backgroundColor: const Color(0xFF1E1C3A),
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
const DrawerHeader(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Color(0xFF8A2BE2), Color(0xFFDA70D6)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
child: Text(
'Menu',
style: TextStyle(
color: Colors.white,
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
),
ListTile(
// ✅ Ícone Font Awesome para Configurações
leading: const Icon(FontAwesomeIcons.gear, color: Colors.white),
title: Text(i18n.t('settings_menu_item'), style: const TextStyle(color: Colors.white)),
onTap: () {
Navigator.pop(context);
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => SettingsScreen(
onCurrencyChanged: _handleCurrencyChange,
),
),
);
},
),
ListTile(
// ✅ Ícone Font Awesome para Notificações
leading: const Icon(FontAwesomeIcons.bell, color: Colors.white),
title: Text(i18n.t('notifications'), style: const TextStyle(color: Colors.white)),
onTap: () {
Navigator.pop(context);
Navigator.push(
context,
MaterialPageRoute(builder: (_) => const NotificationSettingsScreen()),
);
},
),
ListTile(
// ✅ Ícone Font Awesome para Perfil
leading: const Icon(FontAwesomeIcons.solidUser, color: Colors.white),
title: Text(i18n.t('profile'), style: const TextStyle(color: Colors.white)),
onTap: () {
Navigator.pop(context);
setState(() {
_selectedIndex = 3;
});
},
),
],
),
),
body: SafeArea(
child: widgetOptions.elementAt(_selectedIndex),
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (_) => const AddTransactionScreen()),
);
if (result == true) {
setState(() {});
}
},
shape: const CircleBorder(),
backgroundColor: Colors.transparent,
elevation: 0,
child: Container(
width: 60,
height: 60,
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient: const LinearGradient(
colors: [Color(0xFF8A2BE2), Color(0xFFDA70D6)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
boxShadow: [
BoxShadow(
color: const Color(0xFFDA70D6).withOpacity(0.5),
spreadRadius: 2,
blurRadius: 10,
offset: const Offset(0, 5),
),
],
),
child: const Icon(Icons.add, color: Colors.white, size: 30),
),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
bottomNavigationBar: BottomAppBar(
color: const Color(0xFF1E1C3A),
shape: const CircularNotchedRectangle(),
notchMargin: 8.0,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
// ✅ Ícones Font Awesome para a BottomNavigationBar
_buildNavItem(0, const Icon(FontAwesomeIcons.house, color: Colors.white, size: 22), i18n.t('home')),
_buildNavItem(1, const Icon(FontAwesomeIcons.wallet, color: Colors.white, size: 22), i18n.t('transactions_menu_item')),
_buildNavItem(2, const Icon(FontAwesomeIcons.chartBar, color: Colors.white, size: 22), i18n.t('statistics_menu_item')),
_buildNavItem(3, const Icon(FontAwesomeIcons.solidUser, color: Colors.white, size: 22), i18n.t('profile')),
],
),
),
);
}
}
class _DashboardMainContent extends StatelessWidget {
const _DashboardMainContent();
@override
Widget build(BuildContext context) {
final i18n = Provider.of<I18nService>(context);
return Consumer<UserStateService>(
builder: (context, userState, child) {
if (userState.status == UserStateStatus.loading) {
return const Center(
child: CircularProgressIndicator(),
);
}
if (userState.status == UserStateStatus.error) {
return Center(
child: Text(
userState.errorMessage ?? 'Não foi possível carregar os dados do usuário.',
style: const TextStyle(color: Colors.white),
textAlign: TextAlign.center,
),
);
}
final user = userState.currentUser;
if (user == null) {
return Center(
child: Text(
i18n.t('user_not_found'),
style: const TextStyle(color: Colors.white),
),
);
}
final locale = Localizations.localeOf(context).languageCode;
final currencySymbol = 'Kz';
final formattedBalance = NumberFormat.currency(
locale: locale,
symbol: currencySymbol,
decimalDigits: 2,
).format(user.currentBalance);
final formattedDate = DateFormat.yMMMd(locale).format(DateTime.now());
return SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
_KzeducaCardRealistic(user: user),
const SizedBox(height: 24),
const SizedBox(height: 16),
GridView.count(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
crossAxisCount: MediaQuery.of(context).size.width < 600 ? 4 : 4,
mainAxisSpacing: 16,
crossAxisSpacing: 16,
children: [
// ✅ Ícones Font Awesome para os atalhos
_QuickActionIcon(
icon: FontAwesomeIcons.rightLeft, // ✅ Ícone para Transferir/Trocar
label: i18n.t('transfer'),
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (_) => const AddTransactionScreen()))),
_QuickActionIcon(
icon: FontAwesomeIcons.arrowDown, // ✅ Ícone para Receber
label: i18n.t('receive'),
onTap: () => Navigator.push(
context,
MaterialPageRoute(builder: (_) => const ReceiveHistoryScreen()),
)),
_QuickActionIcon(
icon: FontAwesomeIcons.gamepad, // ✅ Ícone para Agente
label: "Jogo",
onTap: () => Navigator.pushNamed(context, '/financial_agent')),
_QuickActionIcon(
icon: FontAwesomeIcons.sackDollar, // ✅ Ícone para Poupança
label: i18n.t('simulator'),
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (_) => const SavingsSimulatorScreen()))),
_QuickActionIcon(
icon: FontAwesomeIcons.book, // ✅ Ícone para Aulas
label: i18n.t('lessons'),
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (_) => const LessonsScreen()))),
_QuickActionIcon(
icon: FontAwesomeIcons.trophy, // ✅ Ícone para Desafios
label: i18n.t('challenges'),
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (_) => const ChallengesScreen()))),
_QuickActionIcon(
icon: FontAwesomeIcons.question, // ✅ Ícone para Quiz
label: i18n.t('quiz'),
onTap: () => Navigator.push(context,
MaterialPageRoute(builder: (_) => const QuizScreen()))),
_QuickActionIcon(
icon: FontAwesomeIcons.moneyBillTrendUp, // ✅ Ícone para Orçamento
label: i18n.t('budget'),
onTap: () => Navigator.push(context,
MaterialPageRoute(builder: (_) => const BudgetScreen()))),
],
),
const SizedBox(height: 32),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(
i18n.t('Historic'),
style: const TextStyle(
color: Colors.white,
fontSize: 22,
fontWeight: FontWeight.bold,
),
overflow: TextOverflow.ellipsis,
),
),
],
),
const SizedBox(height: 16),
Consumer<TransactionListNotifier>(
builder: (context, txnList, _) {
final transactions = txnList.transactions;
if (transactions.isEmpty) {
return const Text('Nenhuma transação encontrada.', style: TextStyle(color: Colors.white70));
}
return ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: transactions.length < 3 ? transactions.length : 3,
itemBuilder: (context, index) {
final transaction = transactions[transactions.length - 1 - index];
final color = transaction.type == TransactionType.income ? Colors.green : Colors.red;
final sign = transaction.type == TransactionType.income ? '+' : '-';
final formattedAmount = NumberFormat.currency(
locale: locale,
symbol: currencySymbol,
decimalDigits: 2,
).format(transaction.amount);
final formattedDate = DateFormat.MMMMd(locale).format(transaction.date);
return Padding(
padding: const EdgeInsets.only(bottom: 16.0),
child: Container(
decoration: BoxDecoration(
color: const Color(0xFF2A284B),
borderRadius: BorderRadius.circular(16),
),
child: ListTile(
// ✅ Ícone Font Awesome para a transação
leading: Icon(FontAwesomeIcons.moneyBillTransfer, color: color),
title: Text(transaction.title, style: const TextStyle(color: Colors.white)),
subtitle: Text(formattedDate, style: const TextStyle(color: Colors.white70)),
trailing: Text('$sign$formattedAmount', style: TextStyle(color: color, fontWeight: FontWeight.bold)),
),
),
);
},
);
},
),
],
),
),
);
},
);
}
}
// ✅ NOVO WIDGET para os ícones de ação rápida, para evitar repetição de código.
class _QuickActionIcon extends StatelessWidget {
final IconData? icon;
final String label;
final VoidCallback onTap;
const _QuickActionIcon({
Key? key,
required this.icon,
required this.label,
required this.onTap,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,
child: Column(
children: [
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
gradient: const LinearGradient(
colors: [Color(0xFF2A284B), Color(0xFF1E1C3A)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.3),
spreadRadius: 2,
blurRadius: 10,
offset: const Offset(0, 5),
),
],
),
child: Icon(
icon,
color: const Color(0xFFDA70D6),
size: 28,
),
),
const SizedBox(height: 8),
Text(
label,
style: const TextStyle(color: Colors.white70, fontSize: 12),
textAlign: TextAlign.center,
),
],
),
);
}
}
// ... (Restante do código _KzeducaCardRealistic, CardPatternPainter, etc.)
class _KzeducaCardRealistic extends StatefulWidget {
final app_models.AppUser user;
const _KzeducaCardRealistic({Key? key, required this.user}) : super(key: key);
@override
State<_KzeducaCardRealistic> createState() => _KzeducaCardRealisticState();
}
class _KzeducaCardRealisticState extends State<_KzeducaCardRealistic> {
bool _isBalanceVisible = true;
String _cardNumber = '';
@override
void initState() {
super.initState();
_cardNumber = _generateCardNumber();
}
String _generateCardNumber() {
final math.Random random = math.Random();
String number = '';
for (int i = 0; i < 12; i++) {
number += random.nextInt(10).toString();
}
return '${number.substring(0, 4)} ${number.substring(4, 8)} ${number.substring(8, 12)} ${number.substring(12, 12)}';
}
@override
Widget build(BuildContext context) {
final locale = Localizations.localeOf(context).languageCode;
final currencySymbol = 'Kz';
final formattedBalance = NumberFormat.currency(
locale: locale,
symbol: currencySymbol,
decimalDigits: 2,
).format(widget.user.currentBalance);
final String displayBalance = _isBalanceVisible ? formattedBalance : 'Kz ****';
final balanceIcon = _isBalanceVisible ? Icons.visibility : Icons.visibility_off;
final now = DateTime.now();
final expiryDate = DateFormat('MM/yy').format(DateTime(now.year + 5, now.month));
return Container(
height: 220,
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
gradient: const RadialGradient(
colors: [
Color(0xFF6A1B9A),
Color(0xFF8E24AA),
Color(0xFF4A148C),
Color(0xFF263238),
],
center: Alignment.centerRight,
radius: 1.5,
),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.6),
spreadRadius: 3,
blurRadius: 15,
offset: const Offset(0, 8),
),
BoxShadow(
color: const Color(0xFFDA70D6).withOpacity(0.3),
spreadRadius: 1,
blurRadius: 5,
offset: const Offset(0, 2),
),
],
),
child: ClipRRect(
borderRadius: BorderRadius.circular(20),
child: CustomPaint(
painter: CardPatternPainter(),
child: Padding(
padding: const EdgeInsets.all(24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'KzEduca',
style: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.bold,
letterSpacing: 1.2,
),
),
Text(
'Aprende. Poupa. Progride.',
style: TextStyle(
color: Colors.white.withOpacity(0.8),
fontSize: 10,
fontStyle: FontStyle.italic),
),
],
),
Text(
expiryDate,
style: TextStyle(
color: Colors.white.withOpacity(0.8),
fontSize: 12,
fontWeight: FontWeight.w500,
),
),
],
),
const Spacer(flex: 1),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
width: 50,
height: 35,
child: CustomPaint(
painter: ChipEMVPainter(),
),
),
GestureDetector(
onTap: () {
setState(() {
_isBalanceVisible = !_isBalanceVisible;
});
},
child: Row(
children: [
Text(
displayBalance,
style: const TextStyle(
color: Colors.white,
fontSize: 22,
fontWeight: FontWeight.bold,
),
),
const SizedBox(width: 8),
//Icon(balanceIcon, color: Colors.white, size: 20),
],
),
),
],
),
const Spacer(flex: 1),
Text(
_cardNumber,
style: const TextStyle(
color: Colors.white,
fontSize: 20,
letterSpacing: 4,
fontWeight: FontWeight.w500,
),
),
const Spacer(flex: 1),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.user.username?.toUpperCase() ?? 'UTILIZADOR',
style: const TextStyle(
color: Colors.white,
fontSize: 14,
fontWeight: FontWeight.w600,
letterSpacing: 1.0,
),
),
Text(
'UID: ${widget.user.uid}',
style: const TextStyle(
color: Colors.white70,
fontSize: 10,
),
),
],
),
SizedBox(
width: 40,
height: 30,
child: CustomPaint(
painter: CardLogoPainter(),
),
),
],
),
],
),
),
),
),
);
}
}
class CardPatternPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = Colors.white.withOpacity(0.08)
..style = PaintingStyle.stroke
..strokeWidth = 0.8;
for (int i = -20; i < size.width + 20; i += 30) {
canvas.drawLine(Offset(i.toDouble(), 0), Offset(i.toDouble() - size.height, size.height), paint);
}
for (int i = 0; i < size.height; i += 30) {
canvas.drawLine(Offset(0, i.toDouble()), Offset(size.width, i.toDouble() - size.width), paint);
}
final circlePaint = Paint()
..color = Colors.white.withOpacity(0.04)
..style = PaintingStyle.fill;
final random = math.Random();
for (int i = 0; i < 30; i++) {
final x = random.nextDouble() * size.width;
final y = random.nextDouble() * size.height;
canvas.drawCircle(Offset(x, y), random.nextDouble() * 1.5 + 0.5, circlePaint);
}
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}
class ChipEMVPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final shadowPaint = Paint()..color = Colors.black.withOpacity(0.3);
final rrectShadow = RRect.fromRectAndRadius(
Rect.fromLTWH(2, 2, size.width - 2, size.height - 2), const Radius.circular(6));
canvas.drawRRect(rrectShadow, shadowPaint);
final paintBase = Paint()
..shader = const LinearGradient(
colors: [Color(0xFFD4AF37), Color(0xFFC0992D), Color(0xFFD4AF37)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
).createShader(Rect.fromLTWH(0, 0, size.width, size.height));
final rrectBase = RRect.fromRectAndRadius(
Rect.fromLTWH(0, 0, size.width, size.height), const Radius.circular(6));
canvas.drawRRect(rrectBase, paintBase);
final paintHighlight = Paint()
..shader = const LinearGradient(
colors: [Color(0xFFFFF7AD), Color(0xFFD4AF37)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
).createShader(Rect.fromLTWH(1, 1, size.width - 2, size.height - 2));
final rrectHighlight = RRect.fromRectAndRadius(
Rect.fromLTWH(1, 1, size.width - 2, size.height - 2), const Radius.circular(5));
canvas.drawRRect(rrectHighlight, paintHighlight);
final paintDetails = Paint()
..color = const Color(0xFF8B6B18)
..style = PaintingStyle.fill;
canvas.drawRRect(RRect.fromRectAndRadius(Rect.fromLTWH(size.width * 0.2, size.height * 0.15, size.width * 0.6, size.height * 0.2), const Radius.circular(2)), paintDetails);
canvas.drawRRect(RRect.fromRectAndRadius(Rect.fromLTWH(size.width * 0.2, size.height * 0.65, size.width * 0.6, size.height * 0.2), const Radius.circular(2)), paintDetails);
canvas.drawRect(Rect.fromLTWH(size.width * 0.1, size.height * 0.35, size.width * 0.1, size.height * 0.3), paintDetails);
canvas.drawRect(Rect.fromLTWH(size.width * 0.8, size.height * 0.35, size.width * 0.1, size.height * 0.3), paintDetails);
canvas.drawRect(Rect.fromLTWH(size.width * 0.3, size.height * 0.45, size.width * 0.4, size.height * 0.1), paintDetails);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}
class CardLogoPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..shader = const LinearGradient(
colors: [Color(0xFFFFA000), Color(0xFFFFC107)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
).createShader(Rect.fromLTWH(0, 0, size.width, size.height));
final path = Path();
path.addOval(Rect.fromLTWH(0, 0, size.width * 0.6, size.height));
path.addOval(Rect.fromLTWH(size.width * 0.4, 0, size.width * 0.6, size.height));
canvas.drawPath(path, paint);
final wifiPaint = Paint()
..color = Colors.white.withOpacity(0.7);
final Path wifiPath = Path();
wifiPath.moveTo(size.width * 0.7, size.height * 0.3);
wifiPath.arcTo(
Rect.fromCircle(center: Offset(size.width * 0.8, size.height * 0.7), radius: 10),
-math.pi,
math.pi,
false,
);
canvas.drawPath(wifiPath, wifiPaint);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}