From 0b4d91416e4219915e413c690cd85b32d99c707b Mon Sep 17 00:00:00 2001 From: LMingJian <1312635752@qq.com> Date: Mon, 15 Jan 2024 15:21:15 +0800 Subject: [PATCH] V1.0 --- android/app/build.gradle | 2 +- lib/main.dart | 8 +- lib/pages/home_page2.dart | 246 ++++++++++++------ lib/utils/sql.dart | 10 + linux/flutter/generated_plugin_registrant.cc | 4 + linux/flutter/generated_plugins.cmake | 2 + macos/Flutter/GeneratedPluginRegistrant.swift | 6 + pubspec.lock | 8 + pubspec.yaml | 1 + .../flutter/generated_plugin_registrant.cc | 3 + windows/flutter/generated_plugins.cmake | 2 + 11 files changed, 206 insertions(+), 86 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 298d23c..34f5cdd 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -48,7 +48,7 @@ android { applicationId "com.lmingjian.goods_scanner" // You can update the following values to match your application needs. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. - minSdkVersion flutter.minSdkVersion + minSdkVersion 21 targetSdkVersion flutter.targetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName diff --git a/lib/main.dart b/lib/main.dart index 6127a1a..2f327a7 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:fluttertoast/fluttertoast.dart'; // import 'package:goods_scaner/pages/home_page.dart'; import 'package:goods_scanner/pages/home_page2.dart'; @@ -15,13 +16,11 @@ void main() { class MyApp extends StatelessWidget { const MyApp({super.key}); - static const appTitle = '商品扫描器'; - // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( - title: appTitle, + title: '商品扫描器', theme: ThemeData( // This is the theme of your application. // @@ -41,7 +40,8 @@ class MyApp extends StatelessWidget { colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), useMaterial3: true, ), - home: const GoodsScannerApp(title: appTitle), + builder: FToastBuilder(), + home: const GoodsScannerApp(), debugShowCheckedModeBanner: false, ); } diff --git a/lib/pages/home_page2.dart b/lib/pages/home_page2.dart index c3985ed..3f13b96 100644 --- a/lib/pages/home_page2.dart +++ b/lib/pages/home_page2.dart @@ -1,14 +1,13 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:fluttertoast/fluttertoast.dart'; import 'package:goods_scanner/models/models.dart'; import 'package:goods_scanner/utils/sql.dart'; import 'package:flutter_zxing/flutter_zxing.dart'; import 'package:flutter/foundation.dart'; class GoodsScannerApp extends StatefulWidget { - const GoodsScannerApp({super.key, required this.title}); - - final String title; + const GoodsScannerApp({super.key}); @override State createState() => _GoodsScannerApp(); @@ -21,10 +20,15 @@ class _GoodsScannerApp extends State { final priceController = TextEditingController(); bool isEditing = false; late Goods _goods; + DateTime _lastPressedAt = DateTime(0); + late FToast fToast; @override void initState() { super.initState(); + fToast = FToast(); + // if you want to use context from globally instead of content we need to pass navigatorKey.currentContext! + fToast.init(context); //scanHelper = ScanHelper(); dbHelper = DatabaseHelper(); dbHelper.initDB().whenComplete(() async { @@ -34,71 +38,104 @@ class _GoodsScannerApp extends State { @override Widget build(BuildContext context) { - return Scaffold( - resizeToAvoidBottomInset: false, - appBar: AppBar( - automaticallyImplyLeading: false, - backgroundColor: Theme.of(context).colorScheme.inversePrimary, - title: Text(widget.title), - ), - body: Column( - children: [ - Expanded( - child: Column( - children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: Form( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - TextFormField( - controller: nameController, - decoration: const InputDecoration(labelText: '商品名'), - ), - TextFormField( - controller: priceController, - keyboardType: TextInputType.number, - inputFormatters: [ - FilteringTextInputFormatter.allow( - RegExp(r'[0-9.]')), - ], - decoration: const InputDecoration(labelText: '价格'), - ), - Row( - mainAxisAlignment: MainAxisAlignment.start, + return WillPopScope( + child: Scaffold( + resizeToAvoidBottomInset: false, + appBar: AppBar( + automaticallyImplyLeading: false, + backgroundColor: Theme.of(context).colorScheme.inversePrimary, + title: const Text('商品扫描器'), + ), + body: Column( + children: [ + Expanded( + child: Column( + children: [ + /* + Padding( + padding: const EdgeInsets.all(8.0), + child: Form( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - Container( - margin: const EdgeInsets.symmetric( - vertical: 10), - child: ElevatedButton( - onPressed: addOrEditGoods, - child: const Text('提交'), - )), - ]) - ]))), - Expanded( - flex: 1, - child: SafeArea(child: goodsWidget()), - ) - ], - )), - ], - ), - floatingActionButton: SizedBox( - width: 80, - height: 80, - child: FloatingActionButton( - onPressed: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => const ScanPage(), - ), - ); - }, - child: const Icon(Icons.add), + TextFormField( + controller: nameController, + decoration: + const InputDecoration(labelText: '商品名'), + ), + TextFormField( + controller: priceController, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.allow( + RegExp(r'[0-9.]')), + ], + decoration: + const InputDecoration(labelText: '价格'), + ), + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Container( + margin: const EdgeInsets.symmetric( + vertical: 10), + child: ElevatedButton( + onPressed: addOrEditGoods, + child: const Text('提交'), + )), + ]) + ]))),*/ + Expanded( + flex: 1, + child: SafeArea(child: goodsWidget()), + ) + ], + )), + ], ), - )); + floatingActionButton: SizedBox( + width: 80, + height: 80, + child: FloatingActionButton( + onPressed: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => const ScanPage(), + ), + ); + }, + child: const Icon(Icons.add), + ), + )), + onWillPop: () async { + debugPrint(_lastPressedAt.toString()); + if (_lastPressedAt == DateTime(0) || + DateTime.now().difference(_lastPressedAt) > + const Duration(seconds: 1)) { + _lastPressedAt = DateTime.now(); + _showToast(); + return false; // 不退出 + } + return true; //退出 + }, + ); + } + + _showToast() { + Widget toast = Container( + padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 12.0), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(25.0), + color: Colors.greenAccent, + ), + child: const Text("再按一次退出"), + ); + + fToast.showToast( + child: toast, + gravity: ToastGravity.BOTTOM, + toastDuration: const Duration(seconds: 2), + ); } Future addOrEditGoods() async { @@ -403,12 +440,17 @@ class _ScanResultWidget extends State { Widget build(BuildContext context) { final priceController = TextEditingController(); final priceController2 = TextEditingController(); + dynamic rawCode = ''; FocusNode focusNode = FocusNode(); FocusNode focusNode2 = FocusNode(); return FutureBuilder( future: dbHelper.retrieveGoodsPrice(widget.result?.text), builder: (BuildContext context, AsyncSnapshot> snapshot) { + rawCode = widget.result?.text ?? 'x'; if (snapshot.hasData && snapshot.data!.isNotEmpty) { + // 数据库有数据 + priceController.text = snapshot.data![0].price; + priceController2.text = snapshot.data![0].name; return Center( child: Padding( padding: const EdgeInsets.only(left: 60.0), @@ -436,12 +478,17 @@ class _ScanResultWidget extends State { '原码: ', style: Theme.of(context).textTheme.titleLarge, ), - Text( - widget.result?.text ?? '', - style: Theme.of(context).textTheme.titleLarge, + SizedBox( + width: 200, + child: Text( + widget.result?.text ?? '', + overflow: TextOverflow.ellipsis, + style: Theme.of(context).textTheme.titleLarge, + ), ), ], ), + const SizedBox(height: 5), Row( mainAxisAlignment: MainAxisAlignment.start, children: [ @@ -459,8 +506,8 @@ class _ScanResultWidget extends State { onEditingComplete: () { FocusScope.of(context).requestFocus(focusNode2); }, - decoration: InputDecoration( - hintText: snapshot.data![0].name, + decoration: const InputDecoration( + helperText: '商品名称-已登记', )), ), ], @@ -487,8 +534,8 @@ class _ScanResultWidget extends State { FilteringTextInputFormatter.allow( RegExp(r'[0-9.]')), ], - decoration: InputDecoration( - hintText: snapshot.data![0].price, + decoration: const InputDecoration( + helperText: '单位:元', ), ), ), @@ -499,10 +546,15 @@ class _ScanResultWidget extends State { mainAxisAlignment: MainAxisAlignment.start, children: [ ElevatedButton( - onPressed: widget.onScanAgain, + onPressed: () => updateGoods( + Goods( + code: rawCode.toString(), + name: priceController2.text.toString(), + price: priceController.text.toString()), + context), child: const Text('提交'), ), - const SizedBox(width: 20), + const SizedBox(width: 60), ElevatedButton( onPressed: widget.onScanAgain, child: const Text('继续扫描'), @@ -514,6 +566,7 @@ class _ScanResultWidget extends State { ), ); } else { + // 数据库无数据 return Center( child: Padding( padding: const EdgeInsets.only(left: 60.0), @@ -541,13 +594,17 @@ class _ScanResultWidget extends State { '原码: ', style: Theme.of(context).textTheme.titleLarge, ), - Text( - widget.result?.text ?? '', - style: Theme.of(context).textTheme.titleLarge, + SizedBox( + width: 200, + child: Text( + widget.result?.text ?? '', + overflow: TextOverflow.ellipsis, + style: Theme.of(context).textTheme.titleLarge, + ), ), ], ), - const SizedBox(height: 10), + const SizedBox(height: 5), Row( mainAxisAlignment: MainAxisAlignment.start, children: [ @@ -566,7 +623,7 @@ class _ScanResultWidget extends State { FocusScope.of(context).requestFocus(focusNode2); }, decoration: - const InputDecoration(helperText: '商品名称'), + const InputDecoration(helperText: '商品名称-未登记'), ), ), ], @@ -604,7 +661,12 @@ class _ScanResultWidget extends State { mainAxisAlignment: MainAxisAlignment.start, children: [ ElevatedButton( - onPressed: widget.onScanAgain, + onPressed: () => addGoods( + Goods( + code: rawCode.toString(), + name: priceController2.text.toString(), + price: priceController.text.toString()), + context), child: const Text('提交'), ), const SizedBox(width: 60), @@ -621,6 +683,28 @@ class _ScanResultWidget extends State { } }); } + + Future addGoods(Goods goods, dynamic context) async { + dynamic result = await dbHelper.insertGoods(goods); + debugPrint(result.toString()); + Navigator.of(context).pushAndRemoveUntil( + MaterialPageRoute( + builder: (context) => const GoodsScannerApp(), + ), + (route) => false, + ); + } + + Future updateGoods(Goods goods, dynamic context) async { + dynamic result = await dbHelper.updateGoodsWithCode(goods); + debugPrint(result.toString()); + Navigator.of(context).pushAndRemoveUntil( + MaterialPageRoute( + builder: (context) => const GoodsScannerApp(), + ), + (route) => false, + ); + } } class UnsupportedPlatformWidget extends StatelessWidget { diff --git a/lib/utils/sql.dart b/lib/utils/sql.dart index a26bcc8..bfbe8d3 100644 --- a/lib/utils/sql.dart +++ b/lib/utils/sql.dart @@ -56,6 +56,16 @@ class DatabaseHelper { return result; } + Future updateGoodsWithCode(Goods goods) async { + int result = await db.update( + 'goods', + {'name': goods.name, 'price': goods.price}, + where: "code = ?", + whereArgs: [goods.code], + ); + return result; + } + Future> retrieveGoodsPrice(String? goodsCode) async { final List> queryResult = await db.query('goods', where: "code = ?", whereArgs: [goodsCode]); diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index e71a16d..64a0ece 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -6,6 +6,10 @@ #include "generated_plugin_registrant.h" +#include void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); + file_selector_plugin_register_with_registrar(file_selector_linux_registrar); } diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 2e1de87..91a56d8 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -3,9 +3,11 @@ # list(APPEND FLUTTER_PLUGIN_LIST + file_selector_linux ) list(APPEND FLUTTER_FFI_PLUGIN_LIST + flutter_zxing ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index cccf817..2ac1d4c 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,6 +5,12 @@ import FlutterMacOS import Foundation +import file_selector_macos +import path_provider_foundation +import sqflite func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) } diff --git a/pubspec.lock b/pubspec.lock index d2e7742..4c88c61 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -272,6 +272,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "1.2.0" + fluttertoast: + dependency: "direct main" + description: + name: fluttertoast + sha256: dfdde255317af381bfc1c486ed968d5a43a2ded9c931e87cbecd88767d6a71c1 + url: "https://pub.flutter-io.cn" + source: hosted + version: "8.2.4" glob: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index c525462..23ce61e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -40,6 +40,7 @@ dependencies: sqflite: ^2.3.0 path: any path_provider: ^2.1.0 + fluttertoast: ^8.2.4 dev_dependencies: flutter_test: diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 8b6d468..77ab7a0 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -6,6 +6,9 @@ #include "generated_plugin_registrant.h" +#include void RegisterPlugins(flutter::PluginRegistry* registry) { + FileSelectorWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FileSelectorWindows")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index b93c4c3..6948007 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -3,9 +3,11 @@ # list(APPEND FLUTTER_PLUGIN_LIST + file_selector_windows ) list(APPEND FLUTTER_FFI_PLUGIN_LIST + flutter_zxing ) set(PLUGIN_BUNDLED_LIBRARIES)