E32221324_Iot_Running/lib/screens/result_screen.dart

238 lines
8.4 KiB
Dart

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/material.dart';
import 'main_screen.dart';
class ResultScreen extends StatelessWidget {
final Map<String, dynamic> activityData;
const ResultScreen({Key? key, required this.activityData}) : super(key: key);
Future<void> _saveActivityAndGoHome(BuildContext context) async {
try {
final user = FirebaseAuth.instance.currentUser;
if (user == null) throw Exception("User belum login");
final docRef = FirebaseFirestore.instance.collection('activities').doc(); // buat ID manual
await docRef.set({
'data': {
'userId': user.uid,
'type': activityData['type'] ?? 'non-lintasan',
'jarak': activityData['jarak'] ?? activityData['distance'] ?? 0.0,
'satuan': activityData['satuan'] ?? 'M',
'putaran': activityData['putaran'] ?? 0,
'duration': activityData['duration'],
'startTime': activityData['startTime'],
'timestamp': FieldValue.serverTimestamp(),
}
});
// AMBIL LAPS DARI RTDB DAN SIMPAN JUGA
final rtdb = FirebaseDatabase.instanceFor(
app: Firebase.app(),
databaseURL: "https://ta-running-default-rtdb.asia-southeast1.firebasedatabase.app",
);
final lapsRef = rtdb.ref("activities/${activityData['uidTag']}/laps");
final lapSnap = await lapsRef.get();
final lapData = lapSnap.value;
if (lapData != null && lapData is Map) {
await docRef.update({
'data.laps': lapData,
});
print("✅ Laps disimpan ke Firestore.");
} else {
print("⚠️ Laps tidak ditemukan di RTDB.");
}
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (_) => const MainScreen()),
(route) => false,
);
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Gagal menyimpan aktivitas: $e')),
);
}
}
@override
Widget build(BuildContext context) {
final type = activityData['type'] ?? 'Tidak diketahui';
final rawJarak = activityData['jarak'] ?? activityData['distance'] ?? 0.0;
final satuan = activityData['satuan'] ?? 'M';
final jarak = satuan == 'M' ? rawJarak / 1000.0 : rawJarak;
final putaran = activityData['putaran'] ?? '-';
int? startTimeMillis = activityData['startTime'];
DateTime? startTime;
if (startTimeMillis != null) {
startTime = DateTime.fromMillisecondsSinceEpoch(startTimeMillis);
}
int? durationMillis = activityData['duration'];
String durationFormatted = '-';
if (durationMillis != null) {
final dur = Duration(milliseconds: durationMillis);
durationFormatted = dur.toString().split('.').first.padLeft(8, "0");
} else if (startTime != null) {
final dur = DateTime.now().difference(startTime);
durationFormatted = dur.toString().split('.').first.padLeft(8, "0");
}
// ✅ Format pace jika tersedia
String? paceFormatted;
if (type == 'non-lintasan' && activityData['pace_sec_per_km'] != null) {
final paceSec = (activityData['pace_sec_per_km'] as num).toDouble();
final paceMin = paceSec ~/ 60;
final paceSecRem = (paceSec % 60).round();
paceFormatted = '$paceMin:${paceSecRem.toString().padLeft(2, '0')} /km';
}
String getRunPeriodLabel(DateTime time) {
final hour = time.hour;
if (hour >= 6 && hour <= 10) {
return 'Berlari Pagi';
} else if (hour >= 11 && hour <= 14) {
return 'Berlari Siang';
} else if (hour >= 15 && hour <= 17) {
return 'Berlari Sore';
} else {
return 'Berlari Malam';
}
}
return Scaffold(
backgroundColor: Colors.white,
body: Center(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 40),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'Selamat! Kamu telah menyelesaikan\naktivitas',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 26, fontWeight: FontWeight.w700),
),
const SizedBox(height: 30),
Container(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 24),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.blueAccent.shade200, Colors.blue.shade400],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.4),
offset: const Offset(0, 4),
blurRadius: 8,
),
],
),
child: Column(
children: [
Text(
getRunPeriodLabel(startTime ?? DateTime.now()),
style: const TextStyle(
fontSize: 30,
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 20),
if (type == 'lintasan') ...[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_infoItem('${jarak.toStringAsFixed(2)} KM', 'Jarak'),
_infoItem(durationFormatted, 'Durasi'),
],
),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_infoItem('$putaran', 'Putaran'),
_infoItem('Lintasan', 'Jenis Aktivitas'),
],
),
] else ...[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_infoItem('${jarak.toStringAsFixed(2)} KM', 'Jarak'),
_infoItem(durationFormatted, 'Durasi'),
],
),
if (paceFormatted != null) ...[
const SizedBox(height: 16),
_infoItem(paceFormatted!, 'Pace'),
],
const SizedBox(height: 16),
Text(
'Jenis Aktivitas\nNon-Lintasan',
textAlign: TextAlign.center,
style: const TextStyle(color: Colors.white, fontSize: 15),
),
],
],
),
),
const SizedBox(height: 40),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () => _saveActivityAndGoHome(context),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
padding: const EdgeInsets.symmetric(vertical: 14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(24),
),
),
child: const Text(
'Kembali ke Beranda',
style: TextStyle(fontSize: 16, color: Colors.white),
),
),
),
],
),
),
),
);
}
Widget _infoItem(String value, String label) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
value,
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
const SizedBox(height: 4),
Text(
label,
style: const TextStyle(color: Colors.white70, fontSize: 12),
),
],
);
}
}