Files
blockcatcher/lib/main.dart
2025-10-31 21:54:15 -05:00

150 lines
4.4 KiB
Dart

import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:geolocator/geolocator.dart';
import 'package:geocoding/geocoding.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(const WalkerApp());
}
class WalkerApp extends StatelessWidget {
const WalkerApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Blockcatcher',
theme: ThemeData(primarySwatch: Colors.blue),
home: const TrackingScreen(),
);
}
}
class TrackingScreen extends StatefulWidget {
const TrackingScreen({super.key});
@override
State<TrackingScreen> createState() => _TrackingScreenState();
}
class _TrackingScreenState extends State<TrackingScreen> {
bool _tracking = false;
List<String> _logs = [];
Timer? _timer;
@override
void dispose() {
_timer?.cancel();
super.dispose();
}
Future<void> _startTracking() async {
final permission = await Geolocator.requestPermission();
if (permission == LocationPermission.denied ||
permission == LocationPermission.deniedForever) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Location permission required')),
);
return;
}
setState(() => _tracking = true);
_timer = Timer.periodic(const Duration(seconds: 5), (_) async {
final pos = await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high,
);
final log = '${DateTime.now().toIso8601String()} — (${pos.latitude}, ${pos.longitude})';
setState(() => _logs.insert(0, log));
final timestamp = formatCentralTime(DateTime.now());
await _sendLocationToBackend(pos.latitude, pos.longitude, timestamp);
});
}
String formatCentralTime(DateTime dt) {
// Central Time offset is UTC-5 or UTC-6 depending on daylight saving
// Using DateTime.now().toUtc() + Duration(hours: -5) is one option
// A better way is using timeZoneOffset from a known location
// For simplicity, let's assume Central Standard Time (UTC-6)
final centralTime = dt.toUtc().subtract(const Duration(hours: 5));
// Format as 10.31.25 9:39:08pm
final formatter = DateFormat('MM.dd.yy h:mm:ss a');
return formatter.format(centralTime);
}
Future<void> _sendLocationToBackend(double lat, double lon, String timestamp) async {
final url = Uri.parse('http://sam.local:3008/api/location');
final response = await http.post(
url,
headers: {'Content-Type': 'application/json'},
body: jsonEncode({
'name': "Freddy Krueger",
'latitude': lat,
'longitude': lon,
'timestamp': timestamp,
}),
);
if (response.statusCode != 200) {
debugPrint('Failed to send location: ${response.statusCode}');
} else {
debugPrint('Location sent successfully');
}
}
void _stopTracking() {
_timer?.cancel();
setState(() => _tracking = false);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFFAEBDFF), // <-- your hex color here
appBar: AppBar(
title: const Text('BLOCKCATCHER'),
backgroundColor: const Color(0xFFAEBDFF), // ✅ your color here
),
body: Column(
children: [
const SizedBox(height: 200), // move button closer to top
Center(
child: ElevatedButton(
onPressed: _tracking ? _stopTracking : _startTracking,
style: ElevatedButton.styleFrom(
shape: const CircleBorder(),
padding: const EdgeInsets.all(60),
backgroundColor: _tracking ? Colors.red : Colors.green,
),
child: Icon(
_tracking ? Icons.stop : Icons.play_arrow,
color: Colors.white,
size: 40,
),
),
),
const SizedBox(height: 40),
Expanded(
child: ListView.builder(
itemCount: _logs.length,
itemBuilder: (context, index) => ListTile(
dense: true,
title: Text(
_logs[index],
style: const TextStyle(color: Colors.black87),
),
),
),
),
],
),
);
}
}