On the options page for VMs and CTs it was easy to change the
configs by mistake. To avoid that, added an edit button on the top
of the screen. The toggle buttons will only be enabled if the edit
button is clicked.

Suggested-by: Thomas Lamprecht <t.lampre...@proxmox.com>
Signed-off-by: Shan Shaji <s.sh...@proxmox.com>
---
 lib/bloc/pve_lxc_overview_bloc.dart          | 11 +++++
 lib/bloc/pve_qemu_overview_bloc.dart         | 11 +++++
 lib/states/pve_lxc_overview_state.dart       | 21 ++++++----
 lib/states/pve_qemu_overview_state.dart      | 21 ++++++----
 lib/widgets/pve_config_switch_list_tile.dart |  8 +++-
 lib/widgets/pve_icon_button_widget.dart      | 43 ++++++++++++++++++++
 lib/widgets/pve_lxc_options_widget.dart      | 16 +++++++-
 lib/widgets/pve_lxc_overview.dart            | 22 ++++++----
 lib/widgets/pve_qemu_options_widget.dart     | 17 ++++++++
 lib/widgets/pve_qemu_overview.dart           |  2 +-
 10 files changed, 143 insertions(+), 29 deletions(-)
 create mode 100644 lib/widgets/pve_icon_button_widget.dart

diff --git a/lib/bloc/pve_lxc_overview_bloc.dart 
b/lib/bloc/pve_lxc_overview_bloc.dart
index e287f97..b856006 100644
--- a/lib/bloc/pve_lxc_overview_bloc.dart
+++ b/lib/bloc/pve_lxc_overview_bloc.dart
@@ -89,6 +89,11 @@ class PveLxcOverviewBloc
         yield latestState.rebuild((b) => b..errorMessage = '');
       }
     }
+
+    if (event is LockLxcOptions) {
+      yield latestState
+          .rebuild((b) => b..isOptionsLocked = event.isLockOptions);
+    }
   }
 
   Future<List<PveGuestRRDdataModel>> _preProcessRRDdata() async {
@@ -131,3 +136,9 @@ class RevertPendingLxcConfig extends PveLxcOverviewEvent {
 
   RevertPendingLxcConfig(this.cField);
 }
+
+class LockLxcOptions extends PveLxcOverviewEvent {
+  final bool isLockOptions;
+
+  LockLxcOptions(this.isLockOptions);
+}
diff --git a/lib/bloc/pve_qemu_overview_bloc.dart 
b/lib/bloc/pve_qemu_overview_bloc.dart
index 3d0fd0e..98b1261 100644
--- a/lib/bloc/pve_qemu_overview_bloc.dart
+++ b/lib/bloc/pve_qemu_overview_bloc.dart
@@ -94,6 +94,11 @@ class PveQemuOverviewBloc
         yield latestState.rebuild((b) => b..errorMessage = '');
       }
     }
+
+    if (event is LockQemuOptions) {
+      yield latestState
+          .rebuild((b) => b..isOptionsLocked = event.isLockOptions);
+    }
   }
 
   Future<List<PveGuestRRDdataModel>> _preProcessRRDdata() async {
@@ -136,3 +141,9 @@ class RevertPendingQemuConfig extends PveQemuOverviewEvent {
 
   RevertPendingQemuConfig(this.cField);
 }
+
+class LockQemuOptions extends PveQemuOverviewEvent {
+  final bool isLockOptions;
+
+  LockQemuOptions(this.isLockOptions);
+}
\ No newline at end of file
diff --git a/lib/states/pve_lxc_overview_state.dart 
b/lib/states/pve_lxc_overview_state.dart
index c10c2e7..a162121 100644
--- a/lib/states/pve_lxc_overview_state.dart
+++ b/lib/states/pve_lxc_overview_state.dart
@@ -10,6 +10,7 @@ abstract class PveLxcOverviewState
     implements Built<PveLxcOverviewState, PveLxcOverviewStateBuilder> {
   // Fields
   String get nodeID;
+  bool get isOptionsLocked;
   PveNodesLxcStatusModel? get currentStatus;
   BuiltList<PveGuestRRDdataModel>? get rrdData;
   PveNodesLxcConfigModel? get config;
@@ -20,13 +21,15 @@ abstract class PveLxcOverviewState
           [void Function(PveLxcOverviewStateBuilder) updates]) =
       _$PveLxcOverviewState;
 
-  factory PveLxcOverviewState.init(String nodeID) =>
-      PveLxcOverviewState((b) => b
-        //base
-        ..errorMessage = ''
-        ..isBlank = true
-        ..isLoading = false
-        ..isSuccess = false
-        //class
-        ..nodeID = nodeID);
+  factory PveLxcOverviewState.init(String nodeID) => PveLxcOverviewState(
+        (b) => b
+          //base
+          ..errorMessage = ''
+          ..isBlank = true
+          ..isLoading = false
+          ..isSuccess = false
+          //class
+          ..nodeID = nodeID
+          ..isOptionsLocked = true,
+      );
 }
diff --git a/lib/states/pve_qemu_overview_state.dart 
b/lib/states/pve_qemu_overview_state.dart
index 43201bc..8d8dd96 100644
--- a/lib/states/pve_qemu_overview_state.dart
+++ b/lib/states/pve_qemu_overview_state.dart
@@ -8,6 +8,7 @@ abstract class PveQemuOverviewState
     with PveBaseState
     implements Built<PveQemuOverviewState, PveQemuOverviewStateBuilder> {
   String get nodeID;
+  bool get isOptionsLocked;
   PveQemuStatusModel? get currentStatus;
   BuiltList<PveGuestRRDdataModel>? get rrdData;
   PveNodesQemuConfigModel? get config;
@@ -18,13 +19,15 @@ abstract class PveQemuOverviewState
           [void Function(PveQemuOverviewStateBuilder) updates]) =
       _$PveQemuOverviewState;
 
-  factory PveQemuOverviewState.init(String nodeID) =>
-      PveQemuOverviewState((b) => b
-        //base
-        ..errorMessage = ''
-        ..isBlank = true
-        ..isLoading = false
-        ..isSuccess = false
-        //class
-        ..nodeID = nodeID);
+  factory PveQemuOverviewState.init(String nodeID) => PveQemuOverviewState(
+        (b) => b
+          //base
+          ..errorMessage = ''
+          ..isBlank = true
+          ..isLoading = false
+          ..isSuccess = false
+          //class
+          ..nodeID = nodeID
+          ..isOptionsLocked = true,
+      );
 }
diff --git a/lib/widgets/pve_config_switch_list_tile.dart 
b/lib/widgets/pve_config_switch_list_tile.dart
index c209fbe..1f2e6c0 100644
--- a/lib/widgets/pve_config_switch_list_tile.dart
+++ b/lib/widgets/pve_config_switch_list_tile.dart
@@ -7,6 +7,7 @@ class PveConfigSwitchListTile extends StatelessWidget {
   final Widget? title;
   final ValueChanged<bool>? onChanged;
   final VoidCallback? onDeleted;
+  final bool disable;
 
   const PveConfigSwitchListTile({
     super.key,
@@ -16,6 +17,7 @@ class PveConfigSwitchListTile extends StatelessWidget {
     this.title,
     this.onChanged,
     this.onDeleted,
+    this.disable = false,
   });
   @override
   Widget build(BuildContext context) {
@@ -26,7 +28,11 @@ class PveConfigSwitchListTile extends StatelessWidget {
     return SwitchListTile(
       title: _getTitle(),
       value: pBool ?? value ?? defaultValue!,
-      onChanged: pending != null ? null : onChanged,
+      onChanged: disable
+          ? null
+          : pending != null
+              ? null
+              : onChanged,
     );
   }
 
diff --git a/lib/widgets/pve_icon_button_widget.dart 
b/lib/widgets/pve_icon_button_widget.dart
new file mode 100644
index 0000000..0d30ce8
--- /dev/null
+++ b/lib/widgets/pve_icon_button_widget.dart
@@ -0,0 +1,43 @@
+import 'package:flutter/material.dart';
+
+class PveIconButton extends StatelessWidget {
+  final IconData icon;
+  final String label;
+  final Color? color;
+  final VoidCallback? onPressed;
+
+  const PveIconButton({
+    super.key,
+    required this.icon,
+    required this.label,
+    this.color,
+    this.onPressed,
+  });
+
+  const PveIconButton.edit({
+    super.key,
+    this.color,
+    this.onPressed,
+  })  : icon = Icons.edit,
+        label = 'Edit';
+
+  @override
+  Widget build(BuildContext context) {
+    return TextButton(
+      onPressed: onPressed,
+      child: Row(
+        spacing: 2,
+        children: [
+          Icon(
+            icon,
+            color: color,
+          ),
+          Text(
+            label,
+            style: TextStyle(color: color),
+          ),
+        ],
+      ),
+    );
+  }
+}
diff --git a/lib/widgets/pve_lxc_options_widget.dart 
b/lib/widgets/pve_lxc_options_widget.dart
index 913f4b1..9165020 100644
--- a/lib/widgets/pve_lxc_options_widget.dart
+++ b/lib/widgets/pve_lxc_options_widget.dart
@@ -4,6 +4,7 @@ import 
'package:pve_flutter_frontend/states/pve_lxc_overview_state.dart';
 import 'package:pve_flutter_frontend/widgets/colored_safe_area.dart';
 import 
'package:pve_flutter_frontend/widgets/proxmox_stream_builder_widget.dart';
 import 'package:pve_flutter_frontend/widgets/pve_config_switch_list_tile.dart';
+import 'package:pve_flutter_frontend/widgets/pve_icon_button_widget.dart';
 
 class PveLxcOptions extends StatelessWidget {
   final PveLxcOverviewBloc? lxcBloc;
@@ -18,7 +19,17 @@ class PveLxcOptions extends StatelessWidget {
           if (config != null) {
             return ColoredSafeArea(
               child: Scaffold(
-                appBar: AppBar(),
+                appBar: AppBar(
+                  actions: [
+                    if (state.isOptionsLocked)
+                      PveIconButton.edit(
+                        color: Theme.of(context).colorScheme.onPrimary,
+                        onPressed: () => lxcBloc!.events.add(
+                          LockLxcOptions(false),
+                        ),
+                      )
+                  ],
+                ),
                 body: SingleChildScrollView(
                   child: Column(
                     children: <Widget>[
@@ -27,6 +38,7 @@ class PveLxcOptions extends StatelessWidget {
                         subtitle: Text(config.hostname ?? 'undefined'),
                       ),
                       PveConfigSwitchListTile(
+                        disable: state.isOptionsLocked,
                         title: const Text("Start on boot"),
                         value: config.onboot,
                         defaultValue: false,
@@ -49,6 +61,7 @@ class PveLxcOptions extends StatelessWidget {
                         subtitle: Text("${config.arch}"),
                       ),
                       PveConfigSwitchListTile(
+                        disable: state.isOptionsLocked,
                         title: const Text("/dev/console"),
                         value: config.console,
                         defaultValue: true,
@@ -67,6 +80,7 @@ class PveLxcOptions extends StatelessWidget {
                         subtitle: Text(config.cmode?.name ?? 'tty'),
                       ),
                       PveConfigSwitchListTile(
+                        disable: state.isOptionsLocked,
                         title: const Text("Protection"),
                         value: config.protection,
                         defaultValue: false,
diff --git a/lib/widgets/pve_lxc_overview.dart 
b/lib/widgets/pve_lxc_overview.dart
index 684dfb6..b49c6ea 100644
--- a/lib/widgets/pve_lxc_overview.dart
+++ b/lib/widgets/pve_lxc_overview.dart
@@ -153,14 +153,20 @@ class PveLxcOverview extends StatelessWidget {
                                         state.nodeID,
                                         'lxc')),
                               createActionCard(
-                                  'Options',
-                                  Icons.settings,
-                                  () => Navigator.of(context)
-                                      .push(MaterialPageRoute(
-                                          builder: (context) => PveLxcOptions(
-                                                lxcBloc: lxcBloc,
-                                              ),
-                                          fullscreenDialog: true))),
+                                'Options',
+                                Icons.settings,
+                                () {
+                                  return Navigator.of(context).push(
+                                    MaterialPageRoute(
+                                      builder: (context) => PveLxcOptions(
+                                        lxcBloc: lxcBloc
+                                          ..events.add(LockLxcOptions(true)),
+                                      ),
+                                      fullscreenDialog: true,
+                                    ),
+                                  );
+                                },
+                              ),
                               if (!resourceBloc.latestState.isStandalone)
                                 createActionCard(
                                     'Migrate',
diff --git a/lib/widgets/pve_qemu_options_widget.dart 
b/lib/widgets/pve_qemu_options_widget.dart
index bb1e11a..60b60b3 100644
--- a/lib/widgets/pve_qemu_options_widget.dart
+++ b/lib/widgets/pve_qemu_options_widget.dart
@@ -5,6 +5,7 @@ import 
'package:pve_flutter_frontend/states/pve_qemu_overview_state.dart';
 import 'package:pve_flutter_frontend/widgets/colored_safe_area.dart';
 import 
'package:pve_flutter_frontend/widgets/proxmox_stream_builder_widget.dart';
 import 'package:pve_flutter_frontend/widgets/pve_config_switch_list_tile.dart';
+import 'package:pve_flutter_frontend/widgets/pve_icon_button_widget.dart';
 
 class PveQemuOptions extends StatelessWidget {
   final String guestID;
@@ -26,6 +27,15 @@ class PveQemuOptions extends StatelessWidget {
                     icon: const Icon(Icons.close),
                     onPressed: () => Navigator.of(context).pop(),
                   ),
+                  actions: [
+                    if (state.isOptionsLocked)
+                      PveIconButton.edit(
+                        onPressed: () => bloc.events.add(
+                          LockQemuOptions(false),
+                        ),
+                        color: Theme.of(context).colorScheme.onPrimary,
+                      )
+                  ],
                 ),
                 body: SingleChildScrollView(
                   child: Form(
@@ -38,6 +48,7 @@ class PveQemuOptions extends StatelessWidget {
                           subtitle: Text(config.name ?? 'VM$guestID'),
                         ),
                         PveConfigSwitchListTile(
+                          disable: state.isOptionsLocked,
                           title: const Text("Start on boot"),
                           value: config.onboot,
                           defaultValue: false,
@@ -63,6 +74,7 @@ class PveQemuOptions extends StatelessWidget {
                           subtitle: Text(config.boot ?? 'Disk, Network, USB'),
                         ),
                         PveConfigSwitchListTile(
+                          disable: state.isOptionsLocked,
                           title: const Text("Use tablet for pointer"),
                           value: config.tablet,
                           defaultValue: true,
@@ -77,6 +89,7 @@ class PveQemuOptions extends StatelessWidget {
                           subtitle: Text(config.hotplug ?? 'disk,network,usb'),
                         ),
                         PveConfigSwitchListTile(
+                          disable: state.isOptionsLocked,
                           title: const Text("ACPI support"),
                           value: config.acpi,
                           defaultValue: true,
@@ -87,6 +100,7 @@ class PveQemuOptions extends StatelessWidget {
                               bloc.events.add(RevertPendingQemuConfig('acpi')),
                         ),
                         PveConfigSwitchListTile(
+                          disable: state.isOptionsLocked,
                           title: const Text("KVM hardware virtualization"),
                           value: config.kvm,
                           defaultValue: true,
@@ -97,6 +111,7 @@ class PveQemuOptions extends StatelessWidget {
                               bloc.events.add(RevertPendingQemuConfig('kvm')),
                         ),
                         PveConfigSwitchListTile(
+                          disable: state.isOptionsLocked,
                           title: const Text("Freeze CPU on startup"),
                           value: config.freeze,
                           defaultValue: false,
@@ -107,6 +122,7 @@ class PveQemuOptions extends StatelessWidget {
                               .add(RevertPendingQemuConfig('freeze')),
                         ),
                         PveConfigSwitchListTile(
+                          disable: state.isOptionsLocked,
                           title: const Text("Use local time for RTC"),
                           value: config.localtime,
                           defaultValue: false,
@@ -130,6 +146,7 @@ class PveQemuOptions extends StatelessWidget {
                           subtitle: Text(config.agent ?? 'Default (disabled)'),
                         ),
                         PveConfigSwitchListTile(
+                          disable: state.isOptionsLocked,
                           title: const Text("Protection"),
                           value: config.protection,
                           defaultValue: false,
diff --git a/lib/widgets/pve_qemu_overview.dart 
b/lib/widgets/pve_qemu_overview.dart
index aa91bcc..d347722 100644
--- a/lib/widgets/pve_qemu_overview.dart
+++ b/lib/widgets/pve_qemu_overview.dart
@@ -259,7 +259,7 @@ class PveQemuOverview extends StatelessWidget {
   Route _createOptionsRoute(PveQemuOverviewBloc bloc) {
     return PageRouteBuilder(
       pageBuilder: (context, animation, secondaryAnimation) => Provider.value(
-        value: bloc,
+        value: bloc..events.add(LockQemuOptions(true)),
         child: PveQemuOptions(
           guestID: guestID,
         ),
-- 
2.39.5



_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel

Reply via email to