MIF_E31231027/smart_cycling/lib/screens/history_detail_screen.dart

270 lines
9.2 KiB
Dart

import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import '../widgets/responsive_layout.dart';
class HistoryDetailScreen extends StatelessWidget {
final Map<String, dynamic> historyItem;
const HistoryDetailScreen({super.key, required this.historyItem});
String _formatTime(int seconds) {
bool isNegative = seconds < 0;
int absSecs = seconds.abs();
int m = absSecs ~/ 60;
int s = absSecs % 60;
String result = "${m.toString().padLeft(2, '0')}:${s.toString().padLeft(2, '0')}";
return isNegative ? "+$result" : result;
}
String _formatDate(String dateStr) {
try {
DateTime dt = DateTime.parse(dateStr);
return DateFormat('dd MMMM yyyy, HH:mm', 'id_ID').format(dt);
} catch (e) {
return dateStr;
}
}
@override
Widget build(BuildContext context) {
final isDark = Theme.of(context).brightness == Brightness.dark;
// Parsing Data
double totalDistance = double.tryParse(historyItem['jarak'].toString().replaceAll(RegExp(r'[^0-9.]'), '')) ?? 0;
double traveledDistance = double.tryParse(historyItem['jarak_tempuh'].toString()) ?? 0;
double remainingDistance = totalDistance - traveledDistance;
if (remainingDistance < 0) remainingDistance = 0;
int timeSpentSeconds = int.tryParse(historyItem['waktu_tempuh'].toString()) ?? 0;
int targetTimeSeconds = int.tryParse(historyItem['target_waktu'].toString()) ?? 0;
// Sisa waktu = Target - Terpakai.
// Jika positif (misal 10 - 8 = 2) -> Bagus.
// Jika negatif (misal 10 - 13 = -3) -> Telat, diformat jadi +03:00 di _formatTime.
int remainingTimeSeconds = targetTimeSeconds - timeSpentSeconds;
String speed = historyItem['kecepatan_rata_rata']?.toString() ?? "0";
String status = historyItem['status']?.toString().toUpperCase() ?? "GAGAL";
bool isSuccess = status == "BERHASIL";
return ResponsiveLayout(
child: Scaffold(
extendBodyBehindAppBar: true,
backgroundColor: Colors.transparent,
appBar: AppBar(
title: const Text(
"Detail Perjalanan",
style: TextStyle(fontWeight: FontWeight.bold, color: Colors.white),
),
centerTitle: true,
backgroundColor: Colors.transparent,
elevation: 0,
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.white),
onPressed: () => Navigator.pop(context),
),
),
body: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: [Color(0xFF1A237E), Color(0xFF121212)],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
),
child: SafeArea(
child: SingleChildScrollView(
padding: const EdgeInsets.all(24.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// CARD STATUS
Container(
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: isSuccess
? [const Color(0xFF11998e), const Color(0xFF38ef7d)]
: [const Color(0xFFcb2d3e), const Color(0xFFef473a)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: (isSuccess ? Colors.green : Colors.red).withOpacity(0.3),
blurRadius: 10,
offset: const Offset(0, 5),
)
]
),
child: Column(
children: [
Icon(
isSuccess ? Icons.check_circle_outline : Icons.error_outline,
size: 64,
color: Colors.white,
),
const SizedBox(height: 16),
Text(
isSuccess ? "MISI BERHASIL" : "MISI GAGAL",
style: const TextStyle(
color: Colors.white,
fontSize: 24,
fontWeight: FontWeight.bold,
letterSpacing: 1.2,
),
),
const SizedBox(height: 8),
Text(
_formatDate(historyItem['tanggal'] ?? ''),
style: const TextStyle(
color: Colors.white70,
fontSize: 14,
),
),
],
),
),
const SizedBox(height: 24),
// INFORMASI RUTE
_buildSectionHeader("Informasi Rute", isDark),
_buildDetailTile(
icon: Icons.directions_bike,
title: "Nama Rute",
value: historyItem['nama_rute'] ?? '-',
isDark: isDark,
),
_buildDetailTile(
icon: Icons.straighten,
title: "Jarak Rute",
value: "${historyItem['jarak'] ?? '-'} Km",
isDark: isDark,
),
_buildDetailTile(
icon: Icons.terrain,
title: "Kondisi Medan",
value: historyItem['kondisi_medan'] ?? '-',
isDark: isDark,
),
_buildDetailTile(
icon: Icons.hourglass_top,
title: "Target Waktu Perjalanan",
value: targetTimeSeconds > 0 ? _formatTime(targetTimeSeconds) : "-",
isDark: isDark,
),
const SizedBox(height: 24),
// DETAIL METRIK
_buildSectionHeader("Metrik Perjalanan", isDark),
_buildDetailTile(
icon: Icons.straighten,
title: "Jarak yang ditempuh",
value: "${traveledDistance.toStringAsFixed(2)} km",
subtitle: "Sisa Jarak : ${remainingDistance.toStringAsFixed(2)} km",
isDark: isDark,
),
_buildDetailTile(
icon: Icons.timer,
title: "Waktu yang ditempuh",
value: _formatTime(timeSpentSeconds),
subtitle: "Sisa Waktu : ${_formatTime(remainingTimeSeconds)}",
subtitleColor: remainingTimeSeconds < 0 ? Colors.redAccent : Colors.blueAccent,
isDark: isDark,
),
_buildDetailTile(
icon: Icons.speed,
title: "Kecepatan Rata-rata",
value: "$speed km/jam",
isDark: isDark,
),
],
),
),
),
),
),
);
}
Widget _buildSectionHeader(String title, bool isDark) {
return Padding(
padding: const EdgeInsets.only(bottom: 12.0, left: 4.0),
child: Text(
title,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.white70,
),
),
);
}
Widget _buildDetailTile({
required IconData icon,
required String title,
required String value,
String? subtitle,
Color? subtitleColor,
required bool isDark,
}) {
return Container(
margin: const EdgeInsets.only(bottom: 12),
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.05),
borderRadius: BorderRadius.circular(15),
border: Border.all(color: Colors.white.withOpacity(0.1)),
),
child: Row(
children: [
Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.blueAccent.withOpacity(0.2),
shape: BoxShape.circle,
),
child: Icon(icon, color: Colors.blueAccent, size: 24),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: const TextStyle(
fontSize: 13,
color: Colors.white54,
),
),
const SizedBox(height: 4),
Text(
value,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
if (subtitle != null) ...[
const SizedBox(height: 4),
Text(
subtitle,
style: TextStyle(
fontSize: 13,
color: subtitleColor ?? Colors.blueAccent,
fontWeight: FontWeight.w500,
),
),
]
],
),
),
],
),
);
}
}