feat: introduce FixMate Flutter app and React dashboard
- Add Flutter app shell (FixMateApp/MainScreen) with tabs: Report, Map, My Reports, Settings - Implement capture and review flow (image_picker, geolocator, deterministic mock AI), and local storage (SharedPreferences + photo files on mobile) - Build Map screen with flutter_map, marker clustering, filters, legend, marker details, and external maps deeplink - Add My Reports list (view details, cycle status, delete) and Settings (language toggle via Provider, diagnostics, clear all data) - Introduce JSON i18n loader and LocaleProvider; add EN/BM assets - Define models (Report, enums) and UI badges (severity, status) - Add static React dashboard (Leaflet map with clustering, heatmap toggle, filters incl. date range, queue, detail drawer), i18n (EN/BM), and demo data - Update build/config and platform setup: - Extend pubspec with required packages and register i18n assets - Android: add CAMERA and location permissions; pin NDK version - iOS: add usage descriptions for camera, photo library, location - Gradle properties tuned for Windows/UNC stability - Register desktop plugins (Linux/macOS/Windows) - .gitignore: ignore .kilocode - Overhaul README and replace sample widget test
This commit is contained in:
85
lib/screens/my_reports/my_reports_screen.dart
Normal file
85
lib/screens/my_reports/my_reports_screen.dart
Normal file
@@ -0,0 +1,85 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../services/storage.dart';
|
||||
import '../../models/report.dart';
|
||||
import '../../widgets/report_card.dart';
|
||||
import '../map/map_screen.dart';
|
||||
import '../../l10n/i18n.dart';
|
||||
|
||||
class MyReportsScreen extends StatefulWidget {
|
||||
const MyReportsScreen({super.key});
|
||||
|
||||
@override
|
||||
State<MyReportsScreen> createState() => _MyReportsScreenState();
|
||||
}
|
||||
|
||||
class _MyReportsScreenState extends State<MyReportsScreen> {
|
||||
List<Report> _reports = [];
|
||||
bool _loading = true;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loadReports();
|
||||
}
|
||||
|
||||
Future<void> _loadReports() async {
|
||||
setState(() {
|
||||
_loading = true;
|
||||
});
|
||||
final reports = await StorageService.getReports();
|
||||
setState(() {
|
||||
_reports = reports.reversed.toList(); // newest first
|
||||
_loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
void _onViewReport(Report r) {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (_) => MapReportDetails(report: r)),
|
||||
);
|
||||
}
|
||||
|
||||
void _onDeleted() async {
|
||||
await _loadReports();
|
||||
}
|
||||
|
||||
void _onUpdated(Report updated) async {
|
||||
await _loadReports();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(I18n.t('nav.myReports')),
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.refresh),
|
||||
onPressed: _loadReports,
|
||||
)
|
||||
],
|
||||
),
|
||||
body: _loading
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: _reports.isEmpty
|
||||
? Center(child: Text(I18n.t('map.noReports')))
|
||||
: RefreshIndicator(
|
||||
onRefresh: _loadReports,
|
||||
child: ListView.builder(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
itemCount: _reports.length,
|
||||
itemBuilder: (context, index) {
|
||||
final r = _reports[index];
|
||||
return ReportCard(
|
||||
report: r,
|
||||
onView: () => _onViewReport(r),
|
||||
onDeleted: _onDeleted,
|
||||
onUpdated: _onUpdated,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user