Initial commit
This commit is contained in:
593
lib/main.dart
Normal file
593
lib/main.dart
Normal file
@@ -0,0 +1,593 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_map/flutter_map.dart';
|
||||
import 'package:latlong2/latlong.dart';
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
void main() {
|
||||
runApp(const SmartHelmetApp());
|
||||
}
|
||||
|
||||
class SmartHelmetApp extends StatelessWidget {
|
||||
const SmartHelmetApp({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
|
||||
statusBarColor: Colors.transparent,
|
||||
statusBarIconBrightness: Brightness.light,
|
||||
));
|
||||
|
||||
return MaterialApp(
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: ThemeData(
|
||||
brightness: Brightness.dark,
|
||||
scaffoldBackgroundColor: const Color(0xFF27292B),
|
||||
primaryColor: const Color(0xFF30343B),
|
||||
fontFamily: 'Pretendard',
|
||||
textTheme: const TextTheme(
|
||||
bodyLarge: TextStyle(color: Colors.white),
|
||||
bodyMedium: TextStyle(color: Colors.white70),
|
||||
),
|
||||
appBarTheme: AppBarTheme(
|
||||
backgroundColor: const Color(0xFF27292B),
|
||||
elevation: 0,
|
||||
foregroundColor: Colors.white,
|
||||
),
|
||||
),
|
||||
home: const HomeScreen(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class HomeScreen extends StatefulWidget {
|
||||
const HomeScreen({super.key});
|
||||
|
||||
@override
|
||||
State<HomeScreen> createState() => _HomeScreenState();
|
||||
}
|
||||
|
||||
class _HomeScreenState extends State<HomeScreen> {
|
||||
int _selectedIndex = 0;
|
||||
|
||||
final Map<String, bool> _overviewToggles = {
|
||||
'UV LED': true,
|
||||
'CHARGING': false,
|
||||
'HELMET': true,
|
||||
'FAN': false,
|
||||
};
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
const double horizontalPadding = 29.1;
|
||||
|
||||
return MediaQuery(
|
||||
data: MediaQuery.of(context).copyWith(
|
||||
textScaler: TextScaler.linear(1.0),
|
||||
),
|
||||
child: Scaffold(
|
||||
appBar: null,
|
||||
body: SafeArea(
|
||||
bottom: false,
|
||||
child: Column(
|
||||
children: [
|
||||
_buildCustomHeader(),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: horizontalPadding),
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(height: 3.43),
|
||||
_buildOverviewHeader(),
|
||||
const SizedBox(height: 3.0),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(child: _buildImageCard()),
|
||||
const SizedBox(width: 3.0),
|
||||
Expanded(child: _buildInfoCard()),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 3.0),
|
||||
_buildBatteryStatusCard(),
|
||||
const SizedBox(height: 3.0),
|
||||
_buildOverviewCard(),
|
||||
const SizedBox(height: 3.0),
|
||||
_buildEnvironmentSensorsCard(),
|
||||
const SizedBox(height: 3.0),
|
||||
_buildMyLocationCard(),
|
||||
const SizedBox(height: 3.0),
|
||||
_buildActivityCard(),
|
||||
const SizedBox(height: 32.0),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
bottomNavigationBar: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
height: 0.38,
|
||||
color: const Color(0xFF5C5D5F),
|
||||
),
|
||||
BottomNavigationBar(
|
||||
currentIndex: _selectedIndex,
|
||||
onTap: (index) {
|
||||
setState(() {
|
||||
_selectedIndex = index;
|
||||
});
|
||||
},
|
||||
type: BottomNavigationBarType.fixed,
|
||||
backgroundColor: const Color(0xFF30343B),
|
||||
elevation: 0,
|
||||
selectedItemColor: Colors.white,
|
||||
unselectedItemColor: Colors.white54,
|
||||
showUnselectedLabels: true,
|
||||
selectedFontSize: 12,
|
||||
unselectedFontSize: 12,
|
||||
items: const [
|
||||
BottomNavigationBarItem(icon: Icon(Icons.home), label: 'HOME'),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(Icons.tune), label: 'CONTROL'),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(Icons.location_on), label: 'LOCATION'),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(Icons.history), label: 'HISTORY'),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCustomHeader() {
|
||||
return Container(
|
||||
height: 64.0,
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0xFF30343B),
|
||||
border: Border(bottom: BorderSide(color: Color(0xFF5C5D5F), width: 1.0))),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: Center(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(children: [
|
||||
const Icon(Icons.settings_input_component_outlined,
|
||||
color: Colors.white),
|
||||
const SizedBox(width: 12),
|
||||
Text('SMART HELMET SYSTEMS',
|
||||
style: TextStyle(
|
||||
fontSize: 13.71,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white))
|
||||
]),
|
||||
Text('2025/10/02 ・ 03:19 PM',
|
||||
style: TextStyle(color: Colors.white70, fontSize: 10.67))
|
||||
])));
|
||||
}
|
||||
|
||||
Widget _buildOverviewHeader() {
|
||||
return Container(
|
||||
height: 27.43,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).primaryColor,
|
||||
borderRadius: BorderRadius.circular(5.7)),
|
||||
child: Row(children: [
|
||||
Text('SYSTEM OVERVIEW',
|
||||
style: TextStyle(
|
||||
color: Colors.white.withOpacity(0.9),
|
||||
fontSize: 9.14,
|
||||
fontWeight: FontWeight.bold)),
|
||||
const Spacer(),
|
||||
SizedBox(
|
||||
width: 24,
|
||||
height: 24,
|
||||
child: IconButton(
|
||||
onPressed: () {},
|
||||
icon: const Icon(Icons.search, color: Colors.white),
|
||||
iconSize: 17.14,
|
||||
splashRadius: 18,
|
||||
padding: EdgeInsets.zero)),
|
||||
SizedBox(
|
||||
width: 24,
|
||||
height: 24,
|
||||
child: IconButton(
|
||||
onPressed: () {},
|
||||
icon: const Icon(Icons.notifications_outlined,
|
||||
color: Colors.white),
|
||||
iconSize: 17.14,
|
||||
splashRadius: 18,
|
||||
padding: EdgeInsets.zero))
|
||||
]));
|
||||
}
|
||||
|
||||
Widget _buildImageCard() {
|
||||
return Container(
|
||||
height: 137.0,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).primaryColor,
|
||||
borderRadius: BorderRadius.circular(5.7),
|
||||
),
|
||||
child: Center(
|
||||
child: Image.asset(
|
||||
'assets/images/helmet.png', // 이 경로는 실제 프로젝트에 맞게 확인해주세요.
|
||||
width: 100.0,
|
||||
height: 117.0,
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildInfoCard() {
|
||||
return Container(
|
||||
height: 137.0,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).primaryColor,
|
||||
borderRadius: BorderRadius.circular(5.7)),
|
||||
child: Column(children: [
|
||||
Expanded(
|
||||
child: Row(children: [
|
||||
const Expanded(
|
||||
child: Center(
|
||||
child: Text('Name /\nNumber',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(color: Colors.white70, fontSize: 11)))),
|
||||
const VerticalDivider(color: Colors.white24, thickness: 1),
|
||||
Expanded(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(Icons.person_outline,
|
||||
size: 16, color: Colors.white70),
|
||||
const SizedBox(height: 4),
|
||||
const Text('J.LIM',
|
||||
style:
|
||||
TextStyle(fontWeight: FontWeight.bold, fontSize: 13)),
|
||||
const Text('001',
|
||||
style:
|
||||
TextStyle(fontWeight: FontWeight.bold, fontSize: 13))
|
||||
]))
|
||||
])),
|
||||
const Divider(color: Colors.white24, height: 1),
|
||||
Expanded(
|
||||
child: Row(children: [
|
||||
const Expanded(
|
||||
child: Center(
|
||||
child: Text('STATUS',
|
||||
style: TextStyle(color: Colors.white70, fontSize: 11)))),
|
||||
const VerticalDivider(color: Colors.white24, thickness: 1),
|
||||
Expanded(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Text('UNLOCKED',
|
||||
style: TextStyle(
|
||||
color: Colors.redAccent,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 11)),
|
||||
const SizedBox(height: 4),
|
||||
Row(mainAxisAlignment: MainAxisAlignment.center, children: [
|
||||
Container(
|
||||
width: 7,
|
||||
height: 7,
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.redAccent, shape: BoxShape.circle)),
|
||||
const SizedBox(width: 4),
|
||||
const Text('ACTIVE',
|
||||
style: TextStyle(
|
||||
color: Colors.redAccent,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 11))
|
||||
])
|
||||
]))
|
||||
]))
|
||||
]));
|
||||
}
|
||||
|
||||
Widget _buildBatteryStatusCard() {
|
||||
return Container(
|
||||
height: 132.0,
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).primaryColor,
|
||||
borderRadius: BorderRadius.circular(5.7)),
|
||||
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||
Text('BATTERY STATUS (%)',
|
||||
style: TextStyle(color: Colors.white70, fontSize: 12)),
|
||||
const SizedBox(height: 12),
|
||||
Expanded(
|
||||
child: Row(children: [
|
||||
SizedBox(
|
||||
width: 70,
|
||||
height: 70,
|
||||
child: Stack(fit: StackFit.expand, children: [
|
||||
const CircularProgressIndicator(
|
||||
value: 1.0,
|
||||
strokeWidth: 6,
|
||||
backgroundColor: Colors.white24,
|
||||
valueColor: AlwaysStoppedAnimation<Color>(Colors.green)), // 초록색으로 수정
|
||||
Center(
|
||||
child: Text('100',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyLarge
|
||||
?.copyWith(
|
||||
fontSize: 24, fontWeight: FontWeight.bold)))
|
||||
])),
|
||||
const SizedBox(width: 16),
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text('NOW',
|
||||
style: TextStyle(color: Colors.white70, fontSize: 11)),
|
||||
const SizedBox(height: 4),
|
||||
const Text('사용 중',
|
||||
style: TextStyle(
|
||||
color: Colors.green,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 11))
|
||||
]),
|
||||
const Spacer(),
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text('Solar Panel',
|
||||
style: TextStyle(color: Colors.white70, fontSize: 11)),
|
||||
const SizedBox(height: 4),
|
||||
const Text('전압: 00 전류: 00',
|
||||
style: TextStyle(color: Colors.white, fontSize: 11))
|
||||
])
|
||||
]))
|
||||
]));
|
||||
}
|
||||
|
||||
Widget _buildOverviewCard() {
|
||||
return Container(
|
||||
height: 88.0,
|
||||
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).primaryColor,
|
||||
borderRadius: BorderRadius.circular(5.7)),
|
||||
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||
Text('OVERVIEW', style: TextStyle(color: Colors.white70, fontSize: 11)),
|
||||
const SizedBox(height: 2),
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).scaffoldBackgroundColor,
|
||||
borderRadius: BorderRadius.circular(5.7)),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
_buildOverviewToggleSwitch('UV LED'),
|
||||
_buildOverviewToggleSwitch('CHARGING'),
|
||||
_buildOverviewToggleSwitch('HELMET'),
|
||||
_buildOverviewToggleSwitch('FAN')
|
||||
])))
|
||||
]));
|
||||
}
|
||||
|
||||
Widget _buildEnvironmentSensorsCard() {
|
||||
return Container(
|
||||
height: 88.0,
|
||||
padding: const EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).primaryColor,
|
||||
borderRadius: BorderRadius.circular(5.7)),
|
||||
child: Column(children: [
|
||||
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
|
||||
Text('ENVIRONMENT SENSORS',
|
||||
style: TextStyle(color: Colors.white70, fontSize: 11)),
|
||||
Row(children: [
|
||||
Text('VIEW HISTORY',
|
||||
style: TextStyle(color: Colors.white70, fontSize: 9)),
|
||||
Icon(Icons.arrow_forward_ios, size: 8, color: Colors.white70)
|
||||
])
|
||||
]),
|
||||
const SizedBox(height: 4),
|
||||
Expanded(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildSensorInfoRow(
|
||||
Icons.water_drop_outlined, 'HUMID: 60%'),
|
||||
_buildSensorInfoRow(Icons.thermostat, 'TEMP: 24.5℃')
|
||||
]),
|
||||
const SizedBox(width: 12),
|
||||
const Expanded(child: _LineChartPlaceholder())
|
||||
]))
|
||||
]));
|
||||
}
|
||||
|
||||
Widget _buildMyLocationCard() {
|
||||
final LatLng exampleLocation = LatLng(37.5665, 126.9780);
|
||||
return Container(
|
||||
height: 174.0,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).primaryColor,
|
||||
borderRadius: BorderRadius.circular(5.7),
|
||||
),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(5.7),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 16, 16, 0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('My Location', style: TextStyle(fontSize: 14, color: Colors.white, fontWeight: FontWeight.bold)),
|
||||
SizedBox(height: 4),
|
||||
Text('주소: 금주 남구 효덕로 277', style: TextStyle(fontSize: 12, color: Colors.white70)),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Text('VIEW MORE', style: TextStyle(color: Colors.white70, fontSize: 12)),
|
||||
Icon(Icons.arrow_forward_ios, size: 10, color: Colors.white70),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Expanded(
|
||||
child: FlutterMap(
|
||||
options: MapOptions(
|
||||
initialCenter: exampleLocation,
|
||||
initialZoom: 15.0,
|
||||
),
|
||||
children: [
|
||||
TileLayer(
|
||||
urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
userAgentPackageName: 'com.example.smart_helmet_app',
|
||||
),
|
||||
MarkerLayer(
|
||||
markers: [
|
||||
Marker(
|
||||
point: exampleLocation,
|
||||
width: 80,
|
||||
height: 80,
|
||||
child: const Icon(Icons.location_pin, size: 40, color: Colors.red),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildActivityCard() {
|
||||
return Container(
|
||||
height: 86.0,
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).primaryColor,
|
||||
borderRadius: BorderRadius.circular(5.7)),
|
||||
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||
const Text('Activity',
|
||||
style:
|
||||
TextStyle(fontSize: 12, color: Colors.white, fontWeight: FontWeight.bold)),
|
||||
const SizedBox(height: 8),
|
||||
Expanded(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Text('08:15 AM - Battery fully Charged',
|
||||
style: TextStyle(fontSize: 10, color: Colors.white70)),
|
||||
Text('9:30 AM - UV LED Actived',
|
||||
style: TextStyle(fontSize: 10, color: Colors.white70))
|
||||
])),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Text('10:45 AM - Helmet Unlocked',
|
||||
style: TextStyle(fontSize: 10, color: Colors.white70)),
|
||||
Text('11:00 AM - Helmet Off',
|
||||
style: TextStyle(fontSize: 10, color: Colors.white70))
|
||||
]))
|
||||
]))
|
||||
]));
|
||||
}
|
||||
|
||||
Widget _buildOverviewToggleSwitch(String title) {
|
||||
return Expanded(
|
||||
child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
|
||||
Text(title, style: const TextStyle(fontSize: 9, color: Colors.white)),
|
||||
Transform.scale(
|
||||
scale: 0.6,
|
||||
child: Switch.adaptive(
|
||||
value: _overviewToggles[title]!,
|
||||
onChanged: (bool value) {
|
||||
setState(() {
|
||||
_overviewToggles[title] = value;
|
||||
});
|
||||
},
|
||||
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
activeColor: Colors.white,
|
||||
activeTrackColor: Colors.blueAccent,
|
||||
inactiveThumbColor: Colors.grey.shade400,
|
||||
inactiveTrackColor: Colors.grey.shade700))
|
||||
]));
|
||||
}
|
||||
|
||||
Widget _buildSensorInfoRow(IconData icon, String text) {
|
||||
return Row(children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(4),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withOpacity(0.1), shape: BoxShape.circle),
|
||||
child: Icon(icon, color: Colors.white, size: 10)),
|
||||
const SizedBox(width: 6),
|
||||
Text(text, style: const TextStyle(fontSize: 9, color: Colors.white))
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
class _LineChartPlaceholder extends StatelessWidget {
|
||||
const _LineChartPlaceholder();
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(children: [
|
||||
Expanded(
|
||||
child: CustomPaint(painter: _LineChartPainter(), size: Size.infinite)),
|
||||
const SizedBox(height: 4),
|
||||
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
|
||||
Text('24H AGO', style: TextStyle(fontSize: 8, color: Colors.white54)),
|
||||
Text('12H AGO', style: TextStyle(fontSize: 8, color: Colors.white54)),
|
||||
Text('NOW', style: TextStyle(fontSize: 8, color: Colors.white54))
|
||||
])
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
class _LineChartPainter extends CustomPainter {
|
||||
@override
|
||||
void paint(ui.Canvas canvas, ui.Size size) {
|
||||
final paint = Paint()
|
||||
..color = Colors.white.withOpacity(0.8)
|
||||
..strokeWidth = 1.5
|
||||
..style = PaintingStyle.stroke;
|
||||
|
||||
final path = ui.Path();
|
||||
path.moveTo(0, size.height * 0.6);
|
||||
path.cubicTo(size.width * 0.1, size.height * 0.8, size.width * 0.2, size.height * 0.4, size.width * 0.3, size.height * 0.6);
|
||||
path.cubicTo(size.width * 0.4, size.height * 0.8, size.width * 0.45, size.height * 0.2, size.width * 0.6, size.height * 0.5);
|
||||
path.cubicTo(size.width * 0.75, size.height * 0.8, size.width * 0.8, size.height * 0.3, size.width, size.height * 0.2);
|
||||
canvas.drawPath(path, paint);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(covariant CustomPainter oldDelegate) {
|
||||
return false;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user