Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[gui] ask before closing running terminal #3835

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
2 changes: 0 additions & 2 deletions src/client/gui/lib/before_quit_dialog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,11 @@ import 'switch.dart';
class BeforeQuitDialog extends StatefulWidget {
final Function(bool remember) onStop;
final Function(bool remember) onKeep;
final Function() onClose;

const BeforeQuitDialog({
super.key,
required this.onStop,
required this.onKeep,
required this.onClose,
});

@override
Expand Down
50 changes: 50 additions & 0 deletions src/client/gui/lib/close_terminal_dialog.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import 'package:flutter/material.dart' hide Switch;

import 'confirmation_dialog.dart';
import 'switch.dart';

class CloseTerminalDialog extends StatefulWidget {
final Function() onYes;
final Function() onNo;
final Function(bool doNotAsk) onDoNotAsk;

const CloseTerminalDialog({
super.key,
required this.onYes,
required this.onNo,
required this.onDoNotAsk,
});

@override
State<CloseTerminalDialog> createState() => _CloseTerminalDialogState();
}

class _CloseTerminalDialogState extends State<CloseTerminalDialog> {
var doNotAsk = false;

@override
Widget build(BuildContext context) {
return ConfirmationDialog(
title: 'Are you sure you want to close this terminal?',
body: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
const Text('Its current state will be lost.'),
const SizedBox(height: 12),
Switch(
value: doNotAsk,
label: 'Do not ask me again.',
onChanged: (value) => setState(() => doNotAsk = value),
),
]),
actionText: 'Yes',
onAction: () {
widget.onYes();
widget.onDoNotAsk(doNotAsk);
},
inactionText: 'No',
onInaction: () {
widget.onNo();
widget.onDoNotAsk(doNotAsk);
},
);
}
}
1 change: 0 additions & 1 deletion src/client/gui/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,6 @@ class _AppState extends ConsumerState<App> with WindowListener {
.set(remember ? 'nothing' : 'ask');
windowManager.destroy();
},
onClose: () => Navigator.pop(context),
),
);
}
Expand Down
1 change: 1 addition & 0 deletions src/client/gui/lib/providers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ class GuiSettingNotifier extends AutoDisposeFamilyNotifier<String?, String> {

const onAppCloseKey = 'onAppClose';
const hotkeyKey = 'hotkey';
const askTerminalCloseKey = 'askTerminalClose';
// this provider is set with a value obtained asynchronously in main.dart
final guiSettingProvider = NotifierProvider.autoDispose
.family<GuiSettingNotifier, String?, String>(() {
Expand Down
14 changes: 14 additions & 0 deletions src/client/gui/lib/settings/usage_settings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import 'hotkey.dart';
final primaryNameProvider = clientSettingProvider(primaryNameKey);
final passphraseProvider = daemonSettingProvider(passphraseKey);
final privilegedMountsProvider = daemonSettingProvider(privilegedMountsKey);
final askTerminalCloseProvider = guiSettingProvider(askTerminalCloseKey);

class UsageSettings extends ConsumerWidget {
const UsageSettings({super.key});
Expand All @@ -28,6 +29,9 @@ class UsageSettings extends ConsumerWidget {
return value.valueOrNull?.toBoolOption.toNullable() ?? false;
}));
final hotkey = ref.watch(hotkeyProvider);
final askTerminalClose = ref.watch(askTerminalCloseProvider.select((value) {
return value?.toBoolOption.toNullable() ?? true;
}));

return Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
const Text(
Expand Down Expand Up @@ -71,6 +75,16 @@ class UsageSettings extends ConsumerWidget {
);
},
),
const SizedBox(height: 20),
Switch(
label: 'Ask before closing terminal',
value: askTerminalClose,
trailingSwitch: true,
size: 30,
onChanged: (value) {
ref.read(askTerminalCloseProvider.notifier).set(value.toString());
},
),
]);
}
}
Expand Down
31 changes: 30 additions & 1 deletion src/client/gui/lib/vm_details/terminal_tabs.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:fpdart/fpdart.dart';

import '../close_terminal_dialog.dart';
import '../providers.dart';
import 'terminal.dart';

typedef ShellIds = ({
Expand Down Expand Up @@ -135,6 +138,7 @@ class TerminalTabs extends ConsumerWidget {
final provider = shellIdsProvider(name);
final notifier = provider.notifier;
final (:ids, :currentIndex) = ref.watch(provider);
final askTerminalCloseProvider = guiSettingProvider(askTerminalCloseKey);

final tabsAndShells = ids.mapIndexed((index, shellId) {
final tab = ReorderableDragStartListener(
Expand All @@ -144,7 +148,32 @@ class TerminalTabs extends ConsumerWidget {
title: 'Shell ${shellId.id}',
selected: index == currentIndex,
onTap: () => ref.read(notifier).setCurrent(index),
onClose: () => ref.read(notifier).remove(index),
onClose: () {
final ask = ref.read(askTerminalCloseProvider.select((ask) {
return ask?.toBoolOption.toNullable() ?? true;
}));
final terminalKey = (vmName: name, shellId: shellId);
if (!ask || ref.read(terminalProvider(terminalKey)) == null) {
ref.read(notifier).remove(index);
return;
}
showDialog(
context: context,
barrierDismissible: false,
builder: (context) {
return CloseTerminalDialog(
onYes: () {
Navigator.pop(context);
ref.read(notifier).remove(index);
},
onNo: () => Navigator.pop(context),
onDoNotAsk: (doNotAsk) => ref
.read(askTerminalCloseProvider.notifier)
.set('${!doNotAsk}'),
);
},
);
},
),
);

Expand Down
Loading