Files
flutter_server_box/lib/data/model/ssh/virtual_key.dart
lollipopkit🏳️‍⚧️ 3a615449e3 feat: Windows compatibility (#836)
* feat: win compatibility

* fix

* fix: uptime parse

* opt.: linux uptime accuracy

* fix: windows temperature fetching

* opt.

* opt.: powershell exec

* refactor: address PR review feedback and improve code quality

### Major Improvements:
- **Refactored Windows status parsing**: Broke down large `_getWindowsStatus` method into 13 smaller, focused helper methods for better maintainability and readability
- **Extracted system detection logic**: Created dedicated `SystemDetector` helper class to separate OS detection concerns from ServerProvider
- **Improved concurrency handling**: Implemented proper synchronization for server updates using Future-based locks to prevent race conditions

### Bug Fixes:
- **Fixed CPU percentage parsing**: Removed incorrect '*100' multiplication in BSD CPU parsing (values were already percentages)
- **Enhanced memory parsing**: Added validation and error handling to BSD memory fallback parsing with proper logging
- **Improved uptime parsing**: Added support for multiple Windows date formats and robust error handling with validation
- **Fixed division by zero**: Added safety checks in Swap.usedPercent getter

### Code Quality Enhancements:
- **Added comprehensive documentation**: Documented Windows CPU counter limitations and approach
- **Strengthened error handling**: Added detailed logging and validation throughout parsing methods
- **Improved robustness**: Enhanced BSD CPU parsing with percentage validation and warnings
- **Better separation of concerns**: Each parsing method now has single responsibility

### Files Changed:
- `lib/data/helper/system_detector.dart` (new): System detection helper
- `lib/data/model/server/cpu.dart`: Fixed percentage parsing and added validation
- `lib/data/model/server/memory.dart`: Enhanced fallback parsing and division-by-zero protection
- `lib/data/model/server/server_status_update_req.dart`: Refactored into 13 focused parsing methods
- `lib/data/provider/server.dart`: Improved synchronization and extracted system detection

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor: parse & shell fn struct

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-08-08 16:56:36 +08:00

197 lines
4.7 KiB
Dart

import 'package:fl_lib/fl_lib.dart';
import 'package:flutter/material.dart';
import 'package:server_box/core/extension/context/locale.dart';
import 'package:server_box/data/res/store.dart';
import 'package:xterm/core.dart';
enum VirtualKeyFunc { toggleIME, backspace, clipboard, snippet, file }
enum VirtKey {
esc,
alt,
home,
up,
end,
sftp,
snippet,
tab,
ctrl,
left,
down,
right,
clipboard,
ime,
shift,
pgup,
pgdn,
slash,
backSlash,
underscore,
plus,
equal,
minus,
parenLeft,
parenRight,
bracketLeft,
bracketRight,
braceLeft,
braceRight,
chevronLeft,
chevronRight,
colon,
semicolon,
f1,
f2,
f3,
f4,
f5,
f6,
f7,
f8,
f9,
f10,
f11,
f12,
}
extension VirtKeyX on VirtKey {
/// Used for input to terminal
String? get inputRaw => switch (this) {
VirtKey.slash => '/',
VirtKey.backSlash => '\\',
VirtKey.underscore => '_',
VirtKey.plus => '+',
VirtKey.equal => '=',
VirtKey.minus => '-',
VirtKey.parenLeft => '(',
VirtKey.parenRight => ')',
VirtKey.bracketLeft => '[',
VirtKey.bracketRight => ']',
VirtKey.braceLeft => '{',
VirtKey.braceRight => '}',
VirtKey.chevronLeft => '<',
VirtKey.chevronRight => '>',
VirtKey.colon => ':',
VirtKey.semicolon => ';',
_ => null,
};
/// Used for displaying on UI
String get text {
final t = inputRaw;
if (t != null) return t;
if (this == VirtKey.pgdn) return 'PgDn';
if (this == VirtKey.pgup) return 'PgUp';
if (name.length > 1) {
return name.substring(0, 1).toUpperCase() + name.substring(1);
}
return name;
}
/// Default order of virtual keys
static const defaultOrder = [
VirtKey.esc,
VirtKey.alt,
VirtKey.home,
VirtKey.up,
VirtKey.end,
VirtKey.sftp,
VirtKey.snippet,
VirtKey.tab,
VirtKey.ctrl,
VirtKey.left,
VirtKey.down,
VirtKey.right,
VirtKey.clipboard,
VirtKey.ime,
VirtKey.shift,
];
/// Corresponding [TerminalKey]
TerminalKey? get key => switch (this) {
VirtKey.esc => TerminalKey.escape,
VirtKey.alt => TerminalKey.alt,
VirtKey.home => TerminalKey.home,
VirtKey.up => TerminalKey.arrowUp,
VirtKey.end => TerminalKey.end,
VirtKey.tab => TerminalKey.tab,
VirtKey.ctrl => TerminalKey.control,
VirtKey.left => TerminalKey.arrowLeft,
VirtKey.down => TerminalKey.arrowDown,
VirtKey.right => TerminalKey.arrowRight,
VirtKey.shift => TerminalKey.shift,
VirtKey.pgup => TerminalKey.pageUp,
VirtKey.pgdn => TerminalKey.pageDown,
VirtKey.f1 => TerminalKey.f1,
VirtKey.f2 => TerminalKey.f2,
VirtKey.f3 => TerminalKey.f3,
VirtKey.f4 => TerminalKey.f4,
VirtKey.f5 => TerminalKey.f5,
VirtKey.f6 => TerminalKey.f6,
VirtKey.f7 => TerminalKey.f7,
VirtKey.f8 => TerminalKey.f8,
VirtKey.f9 => TerminalKey.f9,
VirtKey.f10 => TerminalKey.f10,
VirtKey.f11 => TerminalKey.f11,
VirtKey.f12 => TerminalKey.f12,
_ => null,
};
/// Icons for virtual keys
IconData? get icon => switch (this) {
VirtKey.up => Icons.arrow_upward,
VirtKey.left => Icons.arrow_back,
VirtKey.down => Icons.arrow_downward,
VirtKey.right => Icons.arrow_forward,
VirtKey.sftp => Icons.file_open,
VirtKey.snippet => Icons.code,
VirtKey.clipboard => Icons.paste,
VirtKey.ime => Icons.keyboard,
_ => null,
};
// Use [VirtualKeyFunc] instead of [VirtKey]
// This can help linter to enum all [VirtualKeyFunc]
// and make sure all [VirtualKeyFunc] are handled
VirtualKeyFunc? get func => switch (this) {
VirtKey.sftp => VirtualKeyFunc.file,
VirtKey.snippet => VirtualKeyFunc.snippet,
VirtKey.clipboard => VirtualKeyFunc.clipboard,
VirtKey.ime => VirtualKeyFunc.toggleIME,
_ => null,
};
bool get toggleable => switch (this) {
VirtKey.alt || VirtKey.ctrl || VirtKey.shift => true,
_ => false,
};
bool get canLongPress => switch (this) {
VirtKey.up || VirtKey.left || VirtKey.down || VirtKey.right => true,
_ => false,
};
String? get help => switch (this) {
VirtKey.sftp => l10n.virtKeyHelpSFTP,
VirtKey.clipboard => l10n.virtKeyHelpClipboard,
VirtKey.ime => l10n.virtKeyHelpIME,
_ => null,
};
/// - [saveDefaultIfErr] if the stored raw values is invalid, save default order to store
static List<VirtKey> loadFromStore({bool saveDefaultIfErr = true}) {
try {
final ints = Stores.setting.sshVirtKeys.fetch();
return ints.map((e) => VirtKey.values[e]).toList();
} on RangeError {
final ints = defaultOrder.map((e) => e.index).toList();
Stores.setting.sshVirtKeys.put(ints);
} catch (e, s) {
Loggers.app.warning('Failed to load sshVirtKeys', e, s);
}
return defaultOrder;
}
}