2026-08-24 06:37:11 +09:00
|
|
|
import 'package:flutter/material.dart';
|
2026-08-26 19:56:03 +09:00
|
|
|
import 'package:iperf3gui/data/services/iperf3_service.dart';
|
|
|
|
|
import 'package:iperf3gui/domain/services/iperf3_runner.dart';
|
2026-08-24 06:51:06 +09:00
|
|
|
import 'package:iperf3gui/ui/features/test_run/test_run_screen.dart';
|
2026-08-24 06:37:11 +09:00
|
|
|
|
2026-08-26 19:56:03 +09:00
|
|
|
/// Application entry point, and the composition root.
|
2026-08-25 13:46:33 +09:00
|
|
|
///
|
2026-08-26 19:56:03 +09:00
|
|
|
/// This is the only place that names a concrete [Iperf3Runner]. Everything
|
|
|
|
|
/// above the data layer depends on the interface, so swapping the transport —
|
|
|
|
|
/// or running the UI against a fake — touches nothing but this file.
|
2026-08-24 06:51:06 +09:00
|
|
|
Future<void> main() async {
|
|
|
|
|
WidgetsFlutterBinding.ensureInitialized();
|
2026-08-26 19:56:03 +09:00
|
|
|
runApp(Iperf3GuiApp(runner: Iperf3Service()));
|
2026-08-24 06:37:11 +09:00
|
|
|
}
|
|
|
|
|
|
2026-08-24 06:51:06 +09:00
|
|
|
class Iperf3GuiApp extends StatelessWidget {
|
2026-08-26 19:56:03 +09:00
|
|
|
const Iperf3GuiApp({required this.runner, super.key});
|
|
|
|
|
|
|
|
|
|
final Iperf3Runner runner;
|
2026-08-24 06:37:11 +09:00
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
|
return MaterialApp(
|
2026-08-24 06:51:06 +09:00
|
|
|
title: 'iperf3-gui',
|
2026-08-24 06:37:11 +09:00
|
|
|
theme: ThemeData(
|
2026-08-24 06:51:06 +09:00
|
|
|
colorSchemeSeed: Colors.blue,
|
|
|
|
|
useMaterial3: true,
|
2026-08-24 06:37:11 +09:00
|
|
|
),
|
2026-08-26 19:56:03 +09:00
|
|
|
home: TestRunScreen(runner: runner),
|
2026-08-24 06:37:11 +09:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|