diff --git a/lib/pages/boxing_page.dart b/lib/pages/boxing_page.dart index 616040c..194226a 100644 --- a/lib/pages/boxing_page.dart +++ b/lib/pages/boxing_page.dart @@ -85,6 +85,7 @@ class BoxingPage extends StatefulWidget { class _BoxingPageState extends State with WidgetsBindingObserver { static const _androidKeyCodeButtonR1 = 103; + static const _androidKeyCodeButtonL2 = 104; final _scannerService = ScannerService(); final _apiService = ApiService(); @@ -194,6 +195,12 @@ class _BoxingPageState extends State with WidgetsBindingObserver { if (_isModeSwitchKey(event)) { _cycleMode(); } + if (_isFinishBoxKey(event)) { + final hasItems = _visibleManyToOnePackedItems.isNotEmpty; + if (hasItems && _mode == BoxingMode.multiCode) { + _finishManyToOneBox(); + } + } } bool _isModeSwitchKey(KeyEvent event) { @@ -203,6 +210,12 @@ class _BoxingPageState extends State with WidgetsBindingObserver { _androidKeyCodeFromLogicalKey(key) == _androidKeyCodeButtonR1; } + bool _isFinishBoxKey(KeyEvent event) { + final key = event.logicalKey; + return key == LogicalKeyboardKey.gameButtonLeft2 || + _androidKeyCodeFromLogicalKey(key) == _androidKeyCodeButtonL2; + } + int? _androidKeyCodeFromLogicalKey(LogicalKeyboardKey key) { final keyId = key.keyId; const androidPlane = LogicalKeyboardKey.androidPlane; @@ -2504,35 +2517,7 @@ class _BoxingPageState extends State with WidgetsBindingObserver { mainAxisSize: MainAxisSize.min, children: [ _buildManyToOneScanBar(hasScan), - _buildManyToOneSubmitRow(hasScan), - Padding( - padding: const EdgeInsets.fromLTRB(12, 6, 12, 8), - child: SizedBox( - width: double.infinity, - height: 36, - child: OutlinedButton( - onPressed: hasItems ? _finishManyToOneBox : null, - style: OutlinedButton.styleFrom( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - side: BorderSide( - color: hasItems - ? Colors.grey.shade600 - : Colors.grey.shade300, - ), - ), - child: Text( - '完成本箱', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w700, - color: hasItems ? Colors.black87 : Colors.grey.shade400, - ), - ), - ), - ), - ), + _buildManyToOneSubmitRow(hasScan, hasItems), ], ), ); @@ -2586,93 +2571,154 @@ class _BoxingPageState extends State with WidgetsBindingObserver { ); } - Widget _buildManyToOneSubmitRow(bool hasScan) { + Widget _buildManyToOneSubmitRow(bool hasScan, bool hasItems) { return Padding( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 7), + padding: const EdgeInsets.fromLTRB(12, 7, 12, 8), child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ - Text( - '数量', - style: TextStyle( - fontSize: 11, - fontWeight: FontWeight.w600, - color: hasScan ? Colors.black54 : Colors.grey.shade400, - ), - ), - const SizedBox(width: 6), + // Left half: quantity label + input + confirm Expanded( - child: SizedBox( - height: 34, - child: TextField( - controller: _quantityController, - focusNode: _quantityFocusNode, - enabled: hasScan && !_isSubmitting, - keyboardType: TextInputType.none, - inputFormatters: [FilteringTextInputFormatter.digitsOnly], - onChanged: (_) => setState(() {}), - onEditingComplete: () {}, - onSubmitted: (_) => _submitFromKeyboard(), - decoration: InputDecoration( - contentPadding: const EdgeInsets.symmetric(horizontal: 10), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(6), + flex: 1, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + '数量', + style: TextStyle( + fontSize: 11, + fontWeight: FontWeight.w600, + color: hasScan ? Colors.black54 : Colors.grey.shade400, ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(6), - borderSide: BorderSide( - color: _quantityTooHigh - ? Colors.red - : Colors.grey.shade300, + ), + const SizedBox(width: 6), + Expanded( + child: SizedBox( + height: 34, + child: TextField( + controller: _quantityController, + focusNode: _quantityFocusNode, + enabled: hasScan && !_isSubmitting, + keyboardType: TextInputType.none, + inputFormatters: [FilteringTextInputFormatter.digitsOnly], + onChanged: (_) => setState(() {}), + onEditingComplete: () {}, + onSubmitted: (_) => _submitFromKeyboard(), + decoration: InputDecoration( + contentPadding: const EdgeInsets.symmetric(horizontal: 10), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(6), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(6), + borderSide: BorderSide( + color: _quantityTooHigh + ? Colors.red + : Colors.grey.shade300, + ), + ), + disabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(6), + borderSide: BorderSide(color: Colors.grey.shade200), + ), + filled: !hasScan, + fillColor: Colors.grey.shade100, + ), + style: const TextStyle( + fontSize: 15, + fontWeight: FontWeight.w600, + ), ), ), - disabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(6), - borderSide: BorderSide(color: Colors.grey.shade200), + ), + const SizedBox(width: 8), + SizedBox( + height: 34, + child: ElevatedButton( + onPressed: _canSubmit ? _submit : null, + style: ElevatedButton.styleFrom( + backgroundColor: _canSubmit + ? Theme.of(context).colorScheme.primary + : Colors.grey.shade200, + foregroundColor: _canSubmit + ? Colors.white + : Colors.grey.shade400, + padding: const EdgeInsets.symmetric(horizontal: 18), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6), + ), + ), + child: _isSubmitting + ? const SizedBox( + width: 18, + height: 18, + child: CircularProgressIndicator( + strokeWidth: 2, + color: Colors.white, + ), + ) + : const Text( + '确认', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w700, + ), + ), ), - filled: !hasScan, - fillColor: Colors.grey.shade100, ), - style: const TextStyle( - fontSize: 15, - fontWeight: FontWeight.w600, - ), - ), + ], ), ), const SizedBox(width: 8), - SizedBox( - height: 34, - child: ElevatedButton( - onPressed: _canSubmit ? _submit : null, - style: ElevatedButton.styleFrom( - backgroundColor: _canSubmit - ? Theme.of(context).colorScheme.primary - : Colors.grey.shade200, - foregroundColor: _canSubmit - ? Colors.white - : Colors.grey.shade400, - padding: const EdgeInsets.symmetric(horizontal: 18), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(6), + // Right half: 完成本箱 + Expanded( + flex: 1, + child: SizedBox( + height: 34, + child: OutlinedButton( + onPressed: hasItems ? _finishManyToOneBox : null, + style: OutlinedButton.styleFrom( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6), + ), + side: BorderSide( + color: hasItems + ? Colors.grey.shade600 + : Colors.grey.shade300, + ), ), - ), - child: _isSubmitting - ? const SizedBox( - width: 18, - height: 18, - child: CircularProgressIndicator( - strokeWidth: 2, - color: Colors.white, - ), - ) - : const Text( - '确认', + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + '完成本箱', style: TextStyle( fontSize: 14, fontWeight: FontWeight.w700, + color: hasItems ? Colors.black87 : Colors.grey.shade400, ), ), + const SizedBox(width: 6), + Container( + padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 1), + decoration: BoxDecoration( + color: hasItems + ? Colors.grey.shade200 + : Colors.grey.shade100, + borderRadius: BorderRadius.circular(3), + ), + child: Text( + 'P3', + style: TextStyle( + fontSize: 10, + fontWeight: FontWeight.w700, + color: hasItems ? Colors.black54 : Colors.grey.shade400, + ), + ), + ), + ], + ), + ), ), ), ],