refine multi-code boxing: inline finish button with P3 shortcut
- Move 完成本箱 button to same row as quantity input, each taking half width - Add P3 (BUTTON_L2, key code 104) hardware key support for finishing box - Display P3 shortcut label on the finish button Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -85,6 +85,7 @@ class BoxingPage extends StatefulWidget {
|
||||
|
||||
class _BoxingPageState extends State<BoxingPage> with WidgetsBindingObserver {
|
||||
static const _androidKeyCodeButtonR1 = 103;
|
||||
static const _androidKeyCodeButtonL2 = 104;
|
||||
|
||||
final _scannerService = ScannerService();
|
||||
final _apiService = ApiService();
|
||||
@@ -194,6 +195,12 @@ class _BoxingPageState extends State<BoxingPage> 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<BoxingPage> 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<BoxingPage> 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<BoxingPage> 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,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user