POLISHING STUFF and Smarter AI, and alot i mean.. ALOT OF BUG FIX AND OPTIMIZE

This commit is contained in:
Wowieee4
2026-05-29 15:50:51 +07:00
parent 1110e5a42d
commit d2b3534dde
65 changed files with 4150 additions and 2974 deletions
@@ -8,6 +8,9 @@ import 'package:latlong2/latlong.dart';
import '../../app/injection_container.dart';
import '../../core/errors/friendly_error.dart';
import '../../core/network/api_client.dart';
import '../../core/theme/app_colors.dart';
import '../../core/theme/app_decorations.dart';
import '../../shared/widgets/animations/animations.dart';
import '../../shared/widgets/feature_page.dart';
class GuardianMapScreen extends StatefulWidget {
@@ -106,8 +109,9 @@ class _GuardianMapCard extends StatelessWidget {
final center = _pointFrom(location) ??
(points.isNotEmpty ? points.first : null) ??
const LatLng(-7.2575, 112.7521);
return ClipRRect(
borderRadius: BorderRadius.circular(20),
return Container(
decoration: AppDecorations.card,
clipBehavior: Clip.antiAlias,
child: FlutterMap(
options: MapOptions(initialCenter: center, initialZoom: 16),
children: [
@@ -121,7 +125,7 @@ class _GuardianMapCard extends StatelessWidget {
Polyline(
points: points,
strokeWidth: 4,
color: const Color(0xFF2563EB),
color: AppColors.primaryBlue,
),
],
),
@@ -171,10 +175,18 @@ class _TimelineList extends StatelessWidget {
),
);
}
return ListView.separated(
itemCount: segments.length,
separatorBuilder: (_, __) => const SizedBox(height: 10),
itemBuilder: (_, index) => _TimelineCard(segment: segments[index]),
return ListView(
children: [
StaggerWrapper(
children: [
for (final segment in segments)
Padding(
padding: const EdgeInsets.only(bottom: 10),
child: _TimelineCard(segment: segment),
),
],
),
],
);
}
}
@@ -189,9 +201,10 @@ class _TimelineCard extends StatelessWidget {
return Container(
padding: const EdgeInsets.all(14),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
border: Border.all(color: const Color(0xFFE2E8F0)),
color: AppColors.cardWhite,
borderRadius: AppDecorations.cardRadius,
border: Border.all(color: AppColors.border),
boxShadow: AppDecorations.cardShadow,
),
child: Row(
children: [
@@ -199,10 +212,10 @@ class _TimelineCard extends StatelessWidget {
width: 42,
height: 42,
decoration: BoxDecoration(
color: const Color(0xFFEFF6FF),
borderRadius: BorderRadius.circular(14),
color: AppColors.softBlueBg,
borderRadius: BorderRadius.circular(50),
),
child: Icon(segment.icon, color: const Color(0xFF1D4ED8)),
child: Icon(segment.icon, color: AppColors.primaryBlue),
),
const SizedBox(width: 12),
Expanded(
@@ -8,6 +8,9 @@ import 'package:record/record.dart';
import '../../app/injection_container.dart';
import '../../core/errors/friendly_error.dart';
import '../../core/network/api_client.dart';
import '../../core/theme/app_colors.dart';
import '../../core/theme/app_decorations.dart';
import '../../shared/widgets/animations/animations.dart';
import '../../shared/widgets/feature_page.dart';
class GuardianSendNotifScreen extends StatefulWidget {
@@ -132,132 +135,130 @@ class _GuardianSendNotifScreenState extends State<GuardianSendNotifScreen> {
subtitle: 'Kirim pesan singkat ke User yang sudah pairing',
child: ListView(
children: [
Container(
padding: const EdgeInsets.all(18),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
border: Border.all(color: const Color(0xFFE2E8F0)),
boxShadow: [
BoxShadow(
color: const Color(0xFF1E293B).withValues(alpha: 0.06),
blurRadius: 22,
offset: const Offset(0, 12),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SegmentedButton<bool>(
segments: const [
ButtonSegment(
value: false,
icon: Icon(Icons.message_outlined),
label: Text('Text'),
FadeSlideWrapper(
child: Container(
padding: const EdgeInsets.all(18),
decoration: BoxDecoration(
color: AppColors.cardWhite,
borderRadius: AppDecorations.cardRadius,
border: Border.all(color: AppColors.border),
boxShadow: AppDecorations.cardShadow,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SegmentedButton<bool>(
segments: const [
ButtonSegment(
value: false,
icon: Icon(Icons.message_outlined),
label: Text('Text'),
),
ButtonSegment(
value: true,
icon: Icon(Icons.mic_none_outlined),
label: Text('Voice'),
),
],
selected: {_voiceMode},
onSelectionChanged: _loading || _recording
? null
: (value) => setState(() => _voiceMode = value.first),
),
const SizedBox(height: 14),
TextField(
controller: _message,
minLines: _voiceMode ? 2 : 5,
maxLines: _voiceMode ? 3 : 8,
decoration: const InputDecoration(
labelText: 'Message',
hintText: 'Contoh: Hati-hati, belok kanan setelah pintu.',
prefixIcon: Icon(Icons.message_outlined),
alignLabelWithHint: true,
),
ButtonSegment(
value: true,
icon: Icon(Icons.mic_none_outlined),
label: Text('Voice'),
),
if (_voiceMode) ...[
const SizedBox(height: 14),
Container(
padding: const EdgeInsets.all(14),
decoration: BoxDecoration(
color: const Color(0xFFF8FAFC),
borderRadius: AppDecorations.cardRadius,
border: Border.all(color: AppColors.border),
),
child: Row(
children: [
CircleAvatar(
backgroundColor: _recording
? const Color(0xFFFEE2E2)
: const Color(0xFFEFF6FF),
child: Icon(
_recording ? Icons.graphic_eq : Icons.mic,
color: _recording
? const Color(0xFFDC2626)
: const Color(0xFF2563EB),
),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
_recording
? 'Recording... tap stop when done'
: _voicePath == null
? 'No voice note recorded'
: 'Voice note ready',
style: const TextStyle(
fontWeight: FontWeight.w800),
),
Text(
_recording
? 'Speak clearly near the microphone'
: _voicePath == null
? 'Record a short message for User'
: '${_voiceDuration}s audio attached',
style: const TextStyle(
color: Color(0xFF64748B), fontSize: 12),
),
],
),
),
FilledButton.icon(
onPressed: _loading ? null : _toggleRecording,
icon: Icon(_recording
? Icons.stop
: Icons.fiber_manual_record),
label: Text(_recording ? 'Stop' : 'Record'),
style: FilledButton.styleFrom(
backgroundColor: _recording
? const Color(0xFFDC2626)
: const Color(0xFF2563EB),
),
),
],
),
),
],
selected: {_voiceMode},
onSelectionChanged: _loading || _recording
? null
: (value) => setState(() => _voiceMode = value.first),
),
const SizedBox(height: 14),
TextField(
controller: _message,
minLines: _voiceMode ? 2 : 5,
maxLines: _voiceMode ? 3 : 8,
decoration: const InputDecoration(
labelText: 'Message',
hintText: 'Contoh: Hati-hati, belok kanan setelah pintu.',
prefixIcon: Icon(Icons.message_outlined),
alignLabelWithHint: true,
),
),
if (_voiceMode) ...[
const SizedBox(height: 14),
Container(
padding: const EdgeInsets.all(14),
decoration: BoxDecoration(
color: const Color(0xFFF8FAFC),
borderRadius: BorderRadius.circular(16),
border: Border.all(color: const Color(0xFFE2E8F0)),
),
child: Row(
children: [
CircleAvatar(
backgroundColor: _recording
? const Color(0xFFFEE2E2)
: const Color(0xFFEFF6FF),
child: Icon(
_recording ? Icons.graphic_eq : Icons.mic,
color: _recording
? const Color(0xFFDC2626)
: const Color(0xFF2563EB),
),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
_recording
? 'Recording... tap stop when done'
: _voicePath == null
? 'No voice note recorded'
: 'Voice note ready',
style: const TextStyle(
fontWeight: FontWeight.w800),
),
Text(
_recording
? 'Speak clearly near the microphone'
: _voicePath == null
? 'Record a short message for User'
: '${_voiceDuration}s audio attached',
style: const TextStyle(
color: Color(0xFF64748B), fontSize: 12),
),
],
),
),
FilledButton.icon(
onPressed: _loading ? null : _toggleRecording,
icon: Icon(_recording ? Icons.stop : Icons.fiber_manual_record),
label: Text(_recording ? 'Stop' : 'Record'),
style: FilledButton.styleFrom(
backgroundColor: _recording
? const Color(0xFFDC2626)
: const Color(0xFF2563EB),
),
),
],
),
FilledButton.icon(
onPressed: _loading ? null : _send,
icon: _loading
? const SizedBox(
width: 18,
height: 18,
child: CircularProgressIndicator(strokeWidth: 2),
)
: const Icon(Icons.send),
label: Text(_loading
? 'Sending...'
: _voiceMode
? 'Send Voice Message'
: 'Send Message'),
),
],
const SizedBox(height: 14),
FilledButton.icon(
onPressed: _loading ? null : _send,
icon: _loading
? const SizedBox(
width: 18,
height: 18,
child: CircularProgressIndicator(strokeWidth: 2),
)
: const Icon(Icons.send),
label: Text(_loading
? 'Sending...'
: _voiceMode
? 'Send Voice Message'
: 'Send Message'),
),
],
),
),
),
],
@@ -9,6 +9,9 @@ import '../../app/injection_container.dart';
import '../../core/constants/app_constants.dart';
import '../../core/errors/friendly_error.dart';
import '../../core/network/api_client.dart';
import '../../core/theme/app_colors.dart';
import '../../core/theme/app_decorations.dart';
import '../../shared/widgets/animations/animations.dart';
import '../../core/storage/secure_storage.dart';
import '../../shared/widgets/feature_page.dart';
@@ -49,23 +52,27 @@ class GuardianSettingsScreen extends StatelessWidget {
subtitle: 'Account, pairing, AI tools, and server',
child: ListView(
children: [
_SettingsTile(
icon: Icons.link,
title: 'Pair User',
subtitle: 'Masukkan Pairing Code User atau cek status pairing.',
onTap: () => context.go('/guardian/pairing'),
),
_SettingsTile(
icon: Icons.speed,
title: 'AI Benchmark',
subtitle: 'Catat capture, inference, notification, dan TTS.',
onTap: () => context.go('/guardian/benchmark'),
),
_SettingsTile(
icon: Icons.tune,
title: 'AI Config',
subtitle: 'Atur threshold deteksi dan label yang aktif.',
onTap: () => context.go('/guardian/ai-config'),
StaggerWrapper(
children: [
_SettingsTile(
icon: Icons.link,
title: 'Pair User',
subtitle: 'Masukkan Pairing Code User atau cek status pairing.',
onTap: () => context.go('/guardian/pairing'),
),
_SettingsTile(
icon: Icons.speed,
title: 'AI Benchmark',
subtitle: 'Catat capture, inference, notification, dan TTS.',
onTap: () => context.go('/guardian/benchmark'),
),
_SettingsTile(
icon: Icons.tune,
title: 'AI Config',
subtitle: 'Atur threshold deteksi dan label yang aktif.',
onTap: () => context.go('/guardian/ai-config'),
),
],
),
const SizedBox(height: 18),
OutlinedButton.icon(
@@ -103,19 +110,28 @@ class _SettingsTile extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.only(bottom: 10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
border: Border.all(color: const Color(0xFFE2E8F0)),
),
child: ListTile(
leading: Icon(icon, color: const Color(0xFF1D4ED8)),
title: Text(title, style: const TextStyle(fontWeight: FontWeight.w800)),
subtitle: Text(subtitle),
trailing: const Icon(Icons.chevron_right),
onTap: onTap,
return BounceTap(
onTap: onTap,
child: Container(
margin: const EdgeInsets.only(bottom: 10),
decoration: BoxDecoration(
color: AppColors.cardWhite,
borderRadius: AppDecorations.cardRadius,
border: Border.all(color: AppColors.border),
boxShadow: AppDecorations.cardShadow,
),
child: ListTile(
leading: Container(
width: 44,
height: 44,
decoration: AppDecorations.iconCircle(),
child: Icon(icon, color: AppColors.primaryBlue),
),
title:
Text(title, style: const TextStyle(fontWeight: FontWeight.w800)),
subtitle: Text(subtitle),
trailing: const Icon(Icons.chevron_right),
),
),
);
}