add data service and homepage data retrieval

This commit is contained in:
2025-07-24 22:59:50 +01:00
parent e6ed9d01c2
commit 652e83bf38
8 changed files with 157 additions and 20 deletions

Binary file not shown.

View File

@@ -167,7 +167,11 @@ class _LoginPanelContentState extends State<LoginPanelContent> {
}
class RegisterPanelContent extends StatelessWidget {
const RegisterPanelContent({required this.onBack, required this.authService});
const RegisterPanelContent({
super.key,
required this.onBack,
required this.authService,
});
final VoidCallback onBack;
final AuthService authService;
void register() {}

View File

@@ -0,0 +1,58 @@
import 'package:flutter/material.dart';
import 'package:mileograph_flutter/services/authservice.dart';
import 'package:mileograph_flutter/services/dataService.dart';
import 'package:provider/provider.dart';
class Dashboard extends StatelessWidget {
const Dashboard({super.key});
@override
Widget build(BuildContext context) {
final data = context.watch<DataService>();
final auth = context.watch<AuthService>();
return DashboardHeader(auth: auth, data: data);
}
}
class DashboardHeader extends StatelessWidget {
const DashboardHeader({super.key, required this.auth, required this.data});
final AuthService auth;
final DataService data;
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Column(
children: [
Text(
auth.fullName ?? "Unknown",
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
Text.rich(
TextSpan(
children: [
TextSpan(text: "Total Mileage: "),
TextSpan(
text: data.homepageStats?.totalMileage.toString() ?? "0",
),
],
),
),
Text.rich(
TextSpan(
children: [
TextSpan(text: DateTime.now().year.toString()),
TextSpan(text: " Mileage: "),
TextSpan(text: data.getMileageForCurrentYear().toString()),
],
),
),
],
),
],
);
}
}

View File

@@ -2,8 +2,10 @@ import 'package:flutter/material.dart';
import 'package:mileograph_flutter/services/apiService.dart';
import 'package:mileograph_flutter/services/authservice.dart';
import 'package:mileograph_flutter/services/dataService.dart';
import 'package:provider/provider.dart';
import 'components/login/login.dart';
import 'components/pages/dashboard.dart';
late ApiService api;
@@ -39,13 +41,13 @@ void main() {
}
class AppRoot extends StatelessWidget {
const AppRoot({super.key});
@override
Widget build(BuildContext context) {
return Consumer<AuthService>(
builder: (context, auth, child) {
return auth.isLoggedIn
? MyHomePage(title: "Mileograph")
: LoginScreen();
return auth.isLoggedIn ? MyHomePage() : LoginScreen();
},
);
}
@@ -92,7 +94,7 @@ class MyApp extends StatelessWidget {
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
const MyHomePage({super.key});
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
@@ -103,8 +105,6 @@ class MyHomePage extends StatefulWidget {
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
@@ -120,13 +120,22 @@ class _MyHomePageState extends State<MyHomePage> {
];
bool loggedIn = false;
bool _fetched = false;
@override
void didChangeDependencies() {
super.didChangeDependencies();
final data = context.read<DataService>();
if (data.homepageStats == null) {
data.fetchHomepageStats();
if (!_fetched) {
_fetched = true;
WidgetsBinding.instance.addPostFrameCallback((_) {
final data = context.read<DataService>();
final auth = context.read<AuthService>();
api.setTokenProvider(() => auth.token);
if (data.homepageStats == null) {
data.fetchHomepageStats();
}
});
}
}
@@ -135,6 +144,7 @@ class _MyHomePageState extends State<MyHomePage> {
Widget currentPage;
final data = context.watch<DataService>();
final auth = context.read<AuthService>();
if (data.homepageStats != null) {
currentPage = contentPages[pageIndex];
@@ -160,9 +170,26 @@ class _MyHomePageState extends State<MyHomePage> {
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
title: Text.rich(
TextSpan(
children: [
TextSpan(text: "Mile"),
TextSpan(
text: "O",
style: TextStyle(color: Colors.red),
),
TextSpan(text: "graph"),
],
style: TextStyle(
decoration: TextDecoration.none,
color: Colors.white,
fontFamily: "Tomatoes",
),
),
),
actions: [
IconButton(onPressed: null, icon: Icon(Icons.account_circle)),
IconButton(onPressed: auth.logout, icon: Icon(Icons.logout)),
],
),
bottomNavigationBar: NavigationBar(
@@ -189,10 +216,3 @@ class _MyHomePageState extends State<MyHomePage> {
);
}
}
class Dashboard extends StatelessWidget {
Dashboard({super.key});
Widget build(BuildContext context) {
return Text("Logged in");
}
}

View File

@@ -1,6 +1,5 @@
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:mileograph_flutter/services/authservice.dart';
typedef TokenProvider = String? Function();

View File

@@ -1,4 +1,3 @@
import 'package:provider/provider.dart';
import 'package:flutter/foundation.dart';
import 'package:mileograph_flutter/objects/objects.dart';
import 'package:mileograph_flutter/services/apiService.dart';
@@ -65,4 +64,9 @@ class AuthService extends ChangeNotifier {
email: userResponse['email'],
);
}
void logout() {
_user = null;
notifyListeners();
}
}

View File

@@ -0,0 +1,51 @@
import 'package:flutter/foundation.dart';
import 'package:mileograph_flutter/objects/objects.dart';
import 'package:mileograph_flutter/services/apiService.dart'; // assumes you've moved HomepageStats + submodels to a separate file
class DataService extends ChangeNotifier {
final ApiService api;
DataService({required this.api});
HomepageStats? _homepageStats;
HomepageStats? get homepageStats => _homepageStats;
bool _isHomepageLoading = false;
bool get isHomepageLoading => _isHomepageLoading;
Future<void> fetchHomepageStats() async {
_isHomepageLoading = true;
notifyListeners();
try {
final json = await api.get('/stats/homepage');
_homepageStats = HomepageStats.fromJson(json);
} catch (e) {
debugPrint('Failed to fetch homepage stats: $e');
_homepageStats = null;
} finally {
_isHomepageLoading = false;
notifyListeners();
}
}
void clear() {
_homepageStats = null;
notifyListeners();
}
double getMileageForCurrentYear() {
final currentYear = DateTime.now().year;
return getMileageForYear(currentYear) ?? 0;
}
double? getMileageForYear(int year) {
return _homepageStats?.yearlyMileage
.firstWhere(
(entry) => entry.year == year,
orElse: () => YearlyMileage(year: null, mileage: 0),
)
.mileage ??
0;
}
}