E32221324_Iot_Running/lib/screens/start_activity_screen.dart

372 lines
13 KiB
Dart

import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'wait_for_rfid_screen.dart';
class StartActivityScreen extends StatefulWidget {
const StartActivityScreen({super.key});
@override
State<StartActivityScreen> createState() => _StartActivityScreenState();
}
class _StartActivityScreenState extends State<StartActivityScreen> {
String? _selectedType;
final _lapController = TextEditingController(); // Untuk input jumlah putaran
final _calculatedDistanceController = TextEditingController(); // Untuk menampilkan jarak total
String _unit = 'KM';
// Variabel untuk menghitung waktu setiap lap
DateTime lapStartTime = DateTime.now();
DateTime lapEndTime = DateTime.now();
double lapTimeInSeconds = 0;
double speed = 0.0; // Kecepatan dalam m/s
void _showError(String message) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text("Error", style: TextStyle(color: Colors.red)),
content: Text(message),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text("OK", style: TextStyle(color: Colors.blue)),
)
],
),
);
}
// Fungsi untuk memulai timer saat lap dimulai
void startLapTimer() {
lapStartTime = DateTime.now(); // Mulai timer dengan DateTime
}
// Fungsi untuk menghentikan timer saat lap selesai dan menghitung kecepatan
void endLapTimer(double lapDistance, String uidTag) {
lapEndTime = DateTime.now(); // Hentikan timer dengan DateTime
lapTimeInSeconds = lapEndTime.difference(lapStartTime).inSeconds.toDouble(); // Hitung waktu dalam detik
speed = lapDistance / lapTimeInSeconds; // Hitung kecepatan dalam meter per detik
// Simpan kecepatan per lap di Firebase
saveSpeedToFirebase(uidTag, speed);
}
// Fungsi untuk menyimpan kecepatan per lap ke Firebase (RTDB)
void saveSpeedToFirebase(String uidTag, double speed) {
final user = FirebaseAuth.instance.currentUser;
if (user == null) {
print("User tidak ditemukan");
return;
}
try {
final db = FirebaseDatabase.instanceFor(
app: Firebase.app(),
databaseURL: "https://ta-running-default-rtdb.asia-southeast1.firebasedatabase.app",
);
final ref = db.ref("activities/$uidTag");
// Simpan kecepatan per lap
ref.child('kecepatan_lap').push().set({
'speed': speed,
'timestamp': DateTime.now().toIso8601String(),
});
print("Kecepatan lap $uidTag berhasil disimpan: $speed m/s");
} catch (e) {
print("❌ Gagal menyimpan kecepatan lap: $e");
}
}
// Fungsi untuk mengupdate jarak dan kecepatan setiap lap
void _updateDistance() {
final laps = int.tryParse(_lapController.text);
if (laps != null && laps >= 3) {
final totalDistance = laps * 400; // 400 meter per putaran
_calculatedDistanceController.text = totalDistance.toString();
} else if (laps != null && laps < 3) {
_calculatedDistanceController.text = '';
_showError("Jumlah putaran minimal adalah 3 (1200m).");
} else {
_calculatedDistanceController.text = '';
}
}
// Fungsi untuk submit aktivitas ke Firebase
void _submit() {
if (_selectedType == 'Lintasan') {
final laps = int.tryParse(_lapController.text);
if (laps == null || laps < 3) {
_showError("Masukkan jumlah putaran yang valid (minimal 3).");
return;
}
final totalDistance = laps * 400; // 400 meter per putaran
_calculatedDistanceController.text = totalDistance.toString();
submitToFirebase(
jarak: totalDistance.toDouble(),
jenisAktivitas: 'lintasan',
satuan: 'M',
putaran: laps,
);
} else if (_selectedType == 'Non-Lintasan') {
final jarak = double.tryParse(_lapController.text);
if (jarak == null || jarak <= 0) {
_showError("Masukkan jarak yang valid.");
return;
}
submitToFirebase(
jarak: jarak,
jenisAktivitas: 'non-lintasan',
satuan: _unit,
);
} else {
_showError("Pilih jenis aktivitas terlebih dahulu.");
}
}
// Fungsi untuk submit data ke Firebase
void submitToFirebase({
required double jarak,
required String jenisAktivitas,
required String satuan,
int? putaran,
}) async {
final user = FirebaseAuth.instance.currentUser;
if (user == null) {
print("User tidak ditemukan");
return;
}
try {
final userDoc = await FirebaseFirestore.instance
.collection("users")
.doc(user.uid)
.get();
final userData = userDoc.data();
if (userData == null || !userData.containsKey("idGelang")) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("Silakan daftarkan gelang RFID terlebih dahulu.")),
);
return;
}
final uidTag = userData["idGelang"];
final db = FirebaseDatabase.instanceFor(
app: Firebase.app(),
databaseURL: "https://ta-running-default-rtdb.asia-southeast1.firebasedatabase.app",
);
final ref = db.ref("activities/$uidTag");
await ref.set({
'uid_apk': user.uid,
'jarak': jarak,
'satuan': satuan,
'putaran': putaran,
'type': jenisAktivitas,
'status': 'waiting_for_rfid',
'timestamp': DateTime.now().toIso8601String(),
});
print("✅ Data aktivitas dikirim ke Firebase dengan UID tag: $uidTag");
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (_) => WaitForRfidScreen(uidTag: uidTag),
),
);
} catch (e) {
print("❌ Gagal mengirim aktivitas: $e");
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Gagal mengirim aktivitas: $e")),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: PreferredSize(
preferredSize: const Size.fromHeight(80),
child: Container(
decoration: const BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(20),
bottomRight: Radius.circular(20),
),
),
padding: const EdgeInsets.only(top: 40, left: 16, right: 16),
child: Row(
children: [
if (_selectedType != null)
IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.white),
onPressed: () => setState(() => _selectedType = null),
)
else
const SizedBox(width: 48),
Expanded(
child: Center(
child: Text(
"Start Activity",
style: const TextStyle(
color: Colors.white,
fontSize: 28,
fontWeight: FontWeight.bold,
),
),
),
),
const SizedBox(width: 48),
],
),
),
),
body: SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 32),
child: _selectedType == null
? Column(
children: [
const SizedBox(height: 70),
Image.asset(
'images/run.png',
width: 100,
height: 100,
),
const SizedBox(height: 80),
const Text(
'Pilih Jenis Aktivitas',
style: TextStyle(fontSize: 28, fontWeight: FontWeight.w800),
textAlign: TextAlign.center,
),
const SizedBox(height: 28),
Row(
children: [
Expanded(
child: ElevatedButton(
onPressed: () => setState(() => _selectedType = 'Lintasan'),
style: ElevatedButton.styleFrom(
backgroundColor: _selectedType == 'Lintasan' ? Colors.blueAccent : Colors.white,
side: const BorderSide(color: Colors.blueAccent),
foregroundColor: _selectedType == 'Lintasan' ? Colors.white : Colors.blueAccent,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
padding: const EdgeInsets.symmetric(vertical: 14),
),
child: const Text('LINTASAN'),
),
),
const SizedBox(width: 12),
Expanded(
child: ElevatedButton(
onPressed: () => setState(() => _selectedType = 'Non-Lintasan'),
style: ElevatedButton.styleFrom(
backgroundColor: _selectedType == 'Non-Lintasan' ? Colors.blueAccent : Colors.white,
side: const BorderSide(color: Colors.blueAccent),
foregroundColor: _selectedType == 'Non-Lintasan' ? Colors.white : Colors.blueAccent,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
padding: const EdgeInsets.symmetric(vertical: 14),
),
child: const Text('NON-LINTASAN'),
),
),
],
),
],
)
: Column(
children: [
const SizedBox(height: 70),
Image.asset(
'images/run.png',
width: 100,
height: 100,
fit: BoxFit.contain,
),
const SizedBox(height: 80),
Text(
_selectedType!,
style: const TextStyle(fontSize: 28, fontWeight: FontWeight.w800),
),
const SizedBox(height: 20),
if (_selectedType == 'Lintasan') ...[
TextField(
controller: _lapController,
keyboardType: TextInputType.number,
decoration: const InputDecoration(
labelText: 'Jumlah Putaran (400M/Putaran)',
border: OutlineInputBorder(),
),
onChanged: (text) {
_updateDistance(); // Update jarak total setiap kali jumlah putaran diubah
},
),
const SizedBox(height: 12),
TextField(
controller: _calculatedDistanceController,
enabled: false, // Disable editing
decoration: const InputDecoration(
labelText: 'Jarak Total (M)',
border: OutlineInputBorder(),
),
),
] else ...[
Row(
children: [
Expanded(
child: TextField(
controller: _lapController, // Menggunakan lapController untuk Non-Lintasan
keyboardType: TextInputType.number,
decoration: const InputDecoration(
labelText: 'Jarak',
border: OutlineInputBorder(),
),
),
),
const SizedBox(width: 12),
DropdownButton<String>(
value: _unit,
items: const [
DropdownMenuItem(value: 'KM', child: Text('KM')),
DropdownMenuItem(value: 'M', child: Text('M')),
],
onChanged: (value) => setState(() => _unit = value!),
),
],
),
],
const SizedBox(height: 20),
ElevatedButton(
onPressed: _submit,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blueAccent,
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
),
child: const Text(
'Submit dan Scan RFID',
style: TextStyle(fontSize: 16, color: Colors.white),
),
),
],
),
),
);
}
}