From d14e97485f6a8be48fde20e7e1afebf7da979c68 Mon Sep 17 00:00:00 2001 From: GT610 <79314033+GT-610@users.noreply.github.com> Date: Thu, 22 Jan 2026 00:22:23 +0800 Subject: [PATCH] refactor: Optimize process page (#1017) * refactor(process): Optimize the sorting logic of the process list and add a data integrity check flag Add the `_checkedIncompleteData` flag to avoid repeatedly checking data integrity Change `_sortModes` to a final variable and initialize it using `List.from` Remove unnecessary calls to `_timer.cancel` * refactor(process): Remove unused focus states and refactor process item operations Move the stop operation of the process item to the tail button, and remove the focus state-related code that is no longer used * fix(process): Fix the layout of the process page and the stop confirmation dialog box Adjust the spacing condition between CPU and memory display, and only add spacing when both are present Modify the confirmation dialog for stopping the process, and add a cancel button to provide a better user experience * refactor(process): Merge duplicate sorting mode removal logic Combine two separate `removeWhere` calls into one, simplifying the code and enhancing readability --- lib/view/page/process.dart | 71 ++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 37 deletions(-) diff --git a/lib/view/page/process.dart b/lib/view/page/process.dart index 2373a385..08305163 100644 --- a/lib/view/page/process.dart +++ b/lib/view/page/process.dart @@ -29,13 +29,13 @@ class _ProcessPageState extends ConsumerState { SSHClient? _client; PsResult _result = const PsResult(procs: []); - int? _lastFocusId; + bool _checkedIncompleteData = false; // Issue #64 // In cpu mode, the process list will change in a high frequency. // So user will easily know that the list is refreshed. ProcSortMode _procSortMode = ProcSortMode.cpu; - List _sortModes = List.from(ProcSortMode.values); + final _sortModes = List.from(ProcSortMode.values); late final _provider = serverProvider(widget.args.spi.id); @@ -73,18 +73,14 @@ class _ProcessPageState extends ConsumerState { } _result = PsResult.parse(result, sort: _procSortMode); - // If there are any [Proc]'s data is not complete, - // the option to sort by cpu/mem will not be available. - final isAnyProcDataNotComplete = _result.procs.any((e) => e.cpu == null || e.mem == null); - if (isAnyProcDataNotComplete) { - _sortModes.removeWhere((e) => e == ProcSortMode.cpu); - _sortModes.removeWhere((e) => e == ProcSortMode.mem); - } else { - _sortModes = ProcSortMode.values; + if (!_checkedIncompleteData) { + final isAnyProcDataNotComplete = _result.procs.any((e) => e.cpu == null || e.mem == null); + if (isAnyProcDataNotComplete) { + _sortModes.removeWhere((e) => e == ProcSortMode.cpu || e == ProcSortMode.mem); + } + _checkedIncompleteData = true; } setState(() {}); - } else { - _timer.cancel(); } } @@ -145,40 +141,41 @@ class _ProcessPageState extends ConsumerState { title: Text(proc.binary), subtitle: Text(proc.command, style: UIs.textGrey, maxLines: 3, overflow: TextOverflow.fade), trailing: _buildItemTrail(proc), - onTap: () => _lastFocusId = proc.pid, - onLongPress: () { - context.showRoundDialog( - title: libL10n.attention, - child: Text(libL10n.askContinue('${l10n.stop} ${l10n.process}(${proc.pid})')), - actions: Btn.ok( - onTap: () async { - context.pop(); - await context.showLoadingDialog( - fn: () async { - await _client?.run('kill ${proc.pid}'); - await _refresh(); - }, - ); - }, - ).toList, - ); - }, - selected: _lastFocusId == proc.pid, - autofocus: _lastFocusId == proc.pid, ), ); } - Widget? _buildItemTrail(Proc proc) { - if (proc.cpu == null && proc.mem == null) { - return null; - } + Widget _buildItemTrail(Proc proc) { return Row( mainAxisSize: MainAxisSize.min, children: [ if (proc.cpu != null) TwoLineText(up: proc.cpu!.toStringAsFixed(1), down: 'cpu'), - UIs.width13, + if (proc.cpu != null && proc.mem != null) UIs.width13, if (proc.mem != null) TwoLineText(up: proc.mem!.toStringAsFixed(1), down: 'mem'), + if (proc.cpu != null || proc.mem != null) UIs.width13, + IconButton( + icon: const Icon(Icons.stop), + onPressed: () { + context.showRoundDialog( + title: libL10n.attention, + child: Text(libL10n.askContinue('${l10n.stop} ${l10n.process}(${proc.pid})')), + actions: [ + Btn.cancel(), + Btn.ok( + onTap: () async { + context.pop(); + await context.showLoadingDialog( + fn: () async { + await _client?.run('kill ${proc.pid}'); + await _refresh(); + }, + ); + }, + ), + ], + ); + }, + ), ], ); }