diff options
| author | uvok | 2025-07-21 15:23:19 +0200 | 
|---|---|---|
| committer | uvok | 2025-07-21 15:23:19 +0200 | 
| commit | 9532e812f84a089cbf7fe8f35b3fa119fa17d728 (patch) | |
| tree | 95c0ca0a6b5bd83dcb86175356d554b8ad89c91b /lib | |
Add q&d flutter app
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/main.dart | 196 | 
1 files changed, 196 insertions, 0 deletions
| diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..86c82eb --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,196 @@ +import 'package:flutter/material.dart'; + +import 'package:permission_handler/permission_handler.dart'; +import 'package:flutter_blue_plus/flutter_blue_plus.dart'; +import 'package:logger/logger.dart'; + +var logger = Logger(printer: PrettyPrinter()); + +void main() { +  runApp(const MyApp()); +} + +class MyApp extends StatelessWidget { +  const MyApp({super.key}); + +  // This widget is the root of your application. +  @override +  Widget build(BuildContext context) { +    return MaterialApp( +      title: 'Flutter Demo', +      theme: ThemeData( +        // This is the theme of your application. +        // +        // TRY THIS: Try running your application with "flutter run". You'll see +        // the application has a purple toolbar. Then, without quitting the app, +        // try changing the seedColor in the colorScheme below to Colors.green +        // and then invoke "hot reload" (save your changes or press the "hot +        // reload" button in a Flutter-supported IDE, or press "r" if you used +        // the command line to start the app). +        // +        // Notice that the counter didn't reset back to zero; the application +        // state is not lost during the reload. To reset the state, use hot +        // restart instead. +        // +        // This works for code too, not just values: Most code changes can be +        // tested with just a hot reload. +        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), +      ), +      home: const MyHomePage(title: 'Badge Scanner'), +    ); +  } +} + +class MyHomePage extends StatefulWidget { +  const MyHomePage({super.key, required this.title}); + +  // 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 +  // how it looks. + +  // This class is the configuration for the state. It holds the values (in this +  // case the title) provided by the parent (in this case the App widget) and +  // 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(); +} + +class _MyHomePageState extends State<MyHomePage> { +  final List<ScanResult> scanResults = []; +  bool isScanning = false; + +  void _doScan() async { +    setState(() { +      scanResults.clear(); +      isScanning = true; +    }); +    var subscription = FlutterBluePlus.onScanResults.listen( +      onScanResult, +      onError: (e) => logger.e(e), +    ); + +    await FlutterBluePlus.startScan( +      //withServices:[Guid("180D")], // match any of the specified services +      //withNames:["Bluno"], // *or* any of the specified names +      timeout: Duration(seconds: 10), +    ); + +    // wait for scanning to stop +    await FlutterBluePlus.isScanning.where((val) => val == false).first; + +    subscription.cancel(); +    setState(() { +      isScanning = false; +    }); +  } + +  void onScanResult(results) { +    if (results.isNotEmpty) { +      ScanResult r = results.last; // the most recently found device +      logger.i( +        '${r.device.remoteId}: "${r.device.advName}" / "${r.advertisementData.advName}" found!', +      ); +      setState(() { +        scanResults.add(r); +      }); +    } +  } + +  Future getPermissions() async { +    try { +      await Permission.bluetooth.request(); +    } catch (e) { +      logger.e(e.toString()); +    } +  } + +  void btHandler(BluetoothAdapterState event) { +    logger.i(event); +    switch (event) { +      case BluetoothAdapterState.on: +        break; +      default: +        break; +    } +  } + +  @override +  void initState() { +    super.initState(); +    getPermissions(); +    FlutterBluePlus.adapterState.listen(btHandler); +  } + +  @override +  Widget build(BuildContext context) { +    // This method is rerun every time setState is called, for instance as done +    // by the _incrementCounter method above. +    // +    // The Flutter framework has been optimized to make rerunning build methods +    // fast, so that you can just rebuild anything that needs updating rather +    // than having to individually change instances of widgets. +    return Scaffold( +      appBar: AppBar( +        // TRY THIS: Try changing the color here to a specific color (to +        // Colors.amber, perhaps?) and trigger a hot reload to see the AppBar +        // change color while the other colors stay the same. +        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), +      ), +      body: Center( +        // Center is a layout widget. It takes a single child and positions it +        // in the middle of the parent. +        child: Column( +          // Column is also a layout widget. It takes a list of children and +          // arranges them vertically. By default, it sizes itself to fit its +          // children horizontally, and tries to be as tall as its parent. +          // +          // Column has various properties to control how it sizes itself and +          // how it positions its children. Here we use mainAxisAlignment to +          // center the children vertically; the main axis here is the vertical +          // axis because Columns are vertical (the cross axis would be +          // horizontal). +          // +          // 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, +          children: <Widget>[ +            ElevatedButton( +              onPressed: isScanning ? null : _doScan, +              child: isScanning ? Text("Scanning...") : Text("Start scan"), +            ), +            Expanded( +              child: ListView.separated( +                //itemCount: scanResults.length, +                itemBuilder: (context, index) { +                  if (index >= scanResults.length) return null; + +                  final result = scanResults[index]; +                  final name = result.device.advName.isEmpty +                      ? Text("<Unknown>") +                      : Text(result.device.advName); +                  return ListTile( +                    title: name, +                    subtitle: Text(result.device.remoteId.str), +                    trailing: Text('RSSI: ${result.rssi}'), +                  ); +                }, +                separatorBuilder: (BuildContext context, int index) { +                  return Divider(); +                }, +                itemCount: scanResults.length, +              ), +            ), +          ], +        ), +      ), +    ); +  } +} | 
