refact: restore terminals (#12334)

Signed-off-by: fufesou <linlong1266@gmail.com>
This commit is contained in:
fufesou
2025-07-18 11:51:53 +08:00
committed by GitHub
parent 398b0d8d8b
commit bdd3bb946e
6 changed files with 78 additions and 6 deletions

View File

@@ -171,6 +171,8 @@ class _TerminalTabPageState extends State<TerminalTabPage> {
forceRelay: args['forceRelay'],
connToken: args['connToken'],
));
} else if (call.method == kWindowEventRestoreTerminalSessions) {
_restoreSessions(call.arguments);
} else if (call.method == "onDestroy") {
tabController.clear();
} else if (call.method == kWindowActionRebuild) {
@@ -188,6 +190,32 @@ class _TerminalTabPageState extends State<TerminalTabPage> {
super.dispose();
}
Future<void> _restoreSessions(String arguments) async {
Map<String, dynamic>? args;
try {
args = jsonDecode(arguments) as Map<String, dynamic>;
} catch (e) {
debugPrint("Error parsing JSON arguments in _restoreSessions: $e");
return;
}
final persistentSessions =
args['persistent_sessions'] as List<dynamic>? ?? [];
final sortedSessions = persistentSessions.whereType<int>().toList()..sort();
for (final terminalId in sortedSessions) {
_addNewTerminalForCurrentPeer(terminalId: terminalId);
// A delay is required to ensure the UI has sufficient time to update
// before adding the next terminal. Without this delay, `_TerminalPageState::dispose()`
// may be called prematurely while the tab widget is still in the tab controller.
// This behavior is likely due to a race condition between the UI rendering lifecycle
// and the addition of new tabs. Attempts to use `_TerminalPageState::addPostFrameCallback()`
// to wait for the previous page to be ready were unsuccessful, as the observed call sequence is:
// `initState() 2 -> dispose() 2 -> postFrameCallback() 2`, followed by `initState() 3`.
// The `Future.delayed` approach mitigates this issue by introducing a buffer period,
// allowing the UI to stabilize before proceeding.
await Future.delayed(const Duration(milliseconds: 300));
}
}
bool _handleKeyEvent(KeyEvent event) {
if (event is KeyDownEvent) {
// Use Cmd+T on macOS, Ctrl+Shift+T on other platforms
@@ -276,17 +304,20 @@ class _TerminalTabPageState extends State<TerminalTabPage> {
return false;
}
void _addNewTerminal(String peerId) {
void _addNewTerminal(String peerId, {int? terminalId}) {
// Find first tab for this peer to get connection parameters
final firstTab = tabController.state.value.tabs.firstWhere(
(tab) => tab.key.startsWith('$peerId\_'),
);
if (firstTab.page is TerminalPage) {
final page = firstTab.page as TerminalPage;
final terminalId = _nextTerminalId++;
final newTerminalId = terminalId ?? _nextTerminalId++;
if (terminalId != null && terminalId >= _nextTerminalId) {
_nextTerminalId = terminalId + 1;
}
tabController.add(_createTerminalTab(
peerId: peerId,
terminalId: terminalId,
terminalId: newTerminalId,
password: page.password,
isSharedPassword: page.isSharedPassword,
forceRelay: page.forceRelay,
@@ -295,12 +326,12 @@ class _TerminalTabPageState extends State<TerminalTabPage> {
}
}
void _addNewTerminalForCurrentPeer() {
void _addNewTerminalForCurrentPeer({int? terminalId}) {
final currentTab = tabController.state.value.selectedTabInfo;
final parts = currentTab.key.split('_');
if (parts.isNotEmpty) {
final peerId = parts[0];
_addNewTerminal(peerId);
_addNewTerminal(peerId, terminalId: terminalId);
}
}