// Copyright (C) 2025, uvok cheetah // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . import 'package:uvok_epaper_badge/control/scanner_controller.dart'; import 'package:uvok_epaper_badge/widgets/device_details.dart'; import 'package:uvok_epaper_badge/widgets/device_scan_select.dart'; import 'package:uvok_epaper_badge/model/device/device.dart'; import 'package:flutter/material.dart'; import 'package:logger/logger.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:uvok_epaper_badge/model/device_connection.dart'; import 'package:uvok_epaper_badge/model/device_connection_factory.dart'; var logger = Logger(); class ScanPage extends StatefulWidget { const ScanPage({super.key, required this.title, required this.deviceScanner}); // Original doc: Fields in a Widget subclass are always marked "final". final String title; final ScannerController deviceScanner; @override State createState() => _ScanPageState(); } class _ScanPageState extends State { Device? selectedDevice; void _doConnect() async { final Device? dev = selectedDevice; if (dev == null) return; final DeviceConnection connection = DeviceConnectionFactory.createConnection(dev); //??? Navigator.push( context, MaterialPageRoute( builder: (context) => DeviceDetailsScreen(device: dev, deviceConnection: connection), ), ); } void _doScan() async { setState(() { selectedDevice = null; }); // ... await widget.deviceScanner.startScan(); } Future getPermissions() async { try { await Permission.bluetooth.request(); } catch (e) { logger.e(e.toString()); } } @override void initState() { super.initState(); getPermissions(); } @override Widget build(BuildContext context) { return StreamBuilder( stream: widget.deviceScanner.statusStream, initialData: ScanStatus.idle, builder: (context, asyncSnapshot) { bool isScanning = asyncSnapshot.data == ScanStatus.scanning; return Scaffold( appBar: AppBar( backgroundColor: Theme.of(context).colorScheme.inversePrimary, title: Text(widget.title), ), body: Center( child: Column( // TRY THIS: Invoke "debug painting" (choose the "Toggle Debug Paint" // action in the IDE, or press "p" in the console), to see the // wireframe for each widget. mainAxisAlignment: MainAxisAlignment.center, spacing: 24, children: [ SizedBox(height: 15), Row( mainAxisAlignment: MainAxisAlignment.center, spacing: 15.0, children: [ ElevatedButton( onPressed: isScanning ? null : _doScan, child: isScanning ? Text("Scanning...") : Text("Start scan"), ), ElevatedButton( onPressed: (selectedDevice == null || isScanning) ? null : _doConnect, child: Text("Connect"), ), ], ), StreamBuilder( stream: widget.deviceScanner.scanResultsStream, initialData: [], builder: (context, asyncSnapshot) { return DeviceScanSelection( items: asyncSnapshot.data ?? [], onItemSelected: (item) { setState(() => selectedDevice = item); }, ); }, ), ], ), ), ); }, ); } }