[pve-devel] [PATCH pve-flutter-frontend 01/10] avoid elements hiding behind Android softnav buttons

Dominik Csapak d.csapak at proxmox.com
Thu Sep 8 11:55:41 CEST 2022


From: Aaron Lauterer <a.lauterer at proxmox.com>

In a few places we had elements hiding behind the Android soft nav
buttons at the bottom.

Those were:
* Qemu HW overview list
* Qemu Power Control menu
* LXC and Qemu Options list

Placing them within a SafeArea avoids that.

Signed-off-by: Aaron Lauterer <a.lauterer at proxmox.com>
Signed-off-by: Dominik Csapak <d.csapak at proxmox.com>
---
 lib/widgets/pve_lxc_options_widget.dart       | 140 ++++----
 lib/widgets/pve_qemu_options_widget.dart      | 256 +++++++-------
 lib/widgets/pve_qemu_overview.dart            | 319 +++++++++---------
 .../pve_qemu_power_settings_widget.dart       | 178 +++++-----
 4 files changed, 451 insertions(+), 442 deletions(-)

diff --git a/lib/widgets/pve_lxc_options_widget.dart b/lib/widgets/pve_lxc_options_widget.dart
index 89912dc..70db577 100644
--- a/lib/widgets/pve_lxc_options_widget.dart
+++ b/lib/widgets/pve_lxc_options_widget.dart
@@ -15,75 +15,77 @@ class PveLxcOptions extends StatelessWidget {
         builder: (context, state) {
           final config = state.config;
           if (config != null) {
-            return Scaffold(
-              appBar: AppBar(),
-              body: SingleChildScrollView(
-                child: Column(
-                  children: <Widget>[
-                    ListTile(
-                      title: Text("Name"),
-                      subtitle: Text(config.hostname ?? 'undefined'),
-                    ),
-                    PveConfigSwitchListTile(
-                      title: Text("Start on boot"),
-                      value: config.onboot,
-                      defaultValue: false,
-                      pending: config.getPending('onboot'),
-                      onChanged: (v) =>
-                          lxcBloc!.events.add(UpdateLxcConfigBool('onboot', v)),
-                      onDeleted: () =>
-                          lxcBloc!.events.add(RevertPendingLxcConfig('onboot')),
-                    ),
-                    ListTile(
-                      title: Text("Start/Shutdown order"),
-                      subtitle: Text(config.startup ?? "Default (any)"),
-                    ),
-                    ListTile(
-                      title: Text("OS Type"),
-                      subtitle: Text("${config.ostype}"),
-                    ),
-                    ListTile(
-                      title: Text("Architecture"),
-                      subtitle: Text("${config.arch}"),
-                    ),
-                    PveConfigSwitchListTile(
-                      title: Text("/dev/console"),
-                      value: config.console,
-                      defaultValue: true,
-                      pending: config.getPending('console'),
-                      onChanged: (v) => lxcBloc!.events
-                          .add(UpdateLxcConfigBool('console', v)),
-                      onDeleted: () => lxcBloc!.events
-                          .add(RevertPendingLxcConfig('console')),
-                    ),
-                    ListTile(
-                      title: Text("TTY Count"),
-                      subtitle: Text("${config.tty ?? 2}"),
-                    ),
-                    ListTile(
-                      title: Text("Console Mode"),
-                      subtitle: Text(config.cmode?.name ?? 'tty'),
-                    ),
-                    PveConfigSwitchListTile(
-                      title: Text("Protection"),
-                      value: config.protection,
-                      defaultValue: false,
-                      pending: config.getPending('protection'),
-                      onChanged: (v) => lxcBloc!.events
-                          .add(UpdateLxcConfigBool('protection', v)),
-                      onDeleted: () => lxcBloc!.events
-                          .add(RevertPendingLxcConfig('protection')),
-                    ),
-                    ListTile(
-                      title: Text("Unprivileged"),
-                      subtitle:
-                          Text(config.unprivileged ?? false ? 'Yes' : 'No'),
-                    ),
-                    ListTile(
-                      title: Text("Features"),
-                      subtitle: Text(config.features?.toString() ?? 'none'),
-                    ),
-                  ],
+            return SafeArea(
+              child: Scaffold(
+                appBar: AppBar(),
+                body: SingleChildScrollView(
+                  child: Column(
+                    children: <Widget>[
+                      ListTile(
+                        title: Text("Name"),
+                        subtitle: Text(config.hostname ?? 'undefined'),
+                      ),
+                      PveConfigSwitchListTile(
+                        title: Text("Start on boot"),
+                        value: config.onboot,
+                        defaultValue: false,
+                        pending: config.getPending('onboot'),
+                        onChanged: (v) => lxcBloc!.events
+                            .add(UpdateLxcConfigBool('onboot', v)),
+                        onDeleted: () => lxcBloc!.events
+                            .add(RevertPendingLxcConfig('onboot')),
+                      ),
+                      ListTile(
+                        title: Text("Start/Shutdown order"),
+                        subtitle: Text(config.startup ?? "Default (any)"),
+                      ),
+                      ListTile(
+                        title: Text("OS Type"),
+                        subtitle: Text("${config.ostype}"),
+                      ),
+                      ListTile(
+                        title: Text("Architecture"),
+                        subtitle: Text("${config.arch}"),
+                      ),
+                      PveConfigSwitchListTile(
+                        title: Text("/dev/console"),
+                        value: config.console,
+                        defaultValue: true,
+                        pending: config.getPending('console'),
+                        onChanged: (v) => lxcBloc!.events
+                            .add(UpdateLxcConfigBool('console', v)),
+                        onDeleted: () => lxcBloc!.events
+                            .add(RevertPendingLxcConfig('console')),
+                      ),
+                      ListTile(
+                        title: Text("TTY Count"),
+                        subtitle: Text("${config.tty ?? 2}"),
+                      ),
+                      ListTile(
+                        title: Text("Console Mode"),
+                        subtitle: Text(config.cmode?.name ?? 'tty'),
+                      ),
+                      PveConfigSwitchListTile(
+                        title: Text("Protection"),
+                        value: config.protection,
+                        defaultValue: false,
+                        pending: config.getPending('protection'),
+                        onChanged: (v) => lxcBloc!.events
+                            .add(UpdateLxcConfigBool('protection', v)),
+                        onDeleted: () => lxcBloc!.events
+                            .add(RevertPendingLxcConfig('protection')),
+                      ),
+                      ListTile(
+                        title: Text("Unprivileged"),
+                        subtitle:
+                            Text(config.unprivileged ?? false ? 'Yes' : 'No'),
+                      ),
+                      ListTile(
+                        title: Text("Features"),
+                        subtitle: Text(config.features?.toString() ?? 'none'),
+                      ),
+                    ],
+                  ),
                 ),
               ),
             );
diff --git a/lib/widgets/pve_qemu_options_widget.dart b/lib/widgets/pve_qemu_options_widget.dart
index fb28051..788923d 100644
--- a/lib/widgets/pve_qemu_options_widget.dart
+++ b/lib/widgets/pve_qemu_options_widget.dart
@@ -18,134 +18,136 @@ class PveQemuOptions extends StatelessWidget {
         builder: (context, state) {
           if (state.config != null) {
             final config = state.config!;
-            return Scaffold(
-              appBar: AppBar(
-                leading: IconButton(
-                  icon: Icon(Icons.close),
-                  onPressed: () => Navigator.of(context).pop(),
+            return SafeArea(
+              child: Scaffold(
+                appBar: AppBar(
+                  leading: IconButton(
+                    icon: Icon(Icons.close),
+                    onPressed: () => Navigator.of(context).pop(),
+                  ),
                 ),
-              ),
-              body: SingleChildScrollView(
-                child: Form(
-                  key: _formKey,
-                  onChanged: () {},
-                  child: Column(
-                    children: <Widget>[
-                      ListTile(
-                        title: Text("Name"),
-                        subtitle: Text(config.name ?? 'VM$guestID'),
-                      ),
-                      PveConfigSwitchListTile(
-                        title: Text("Start on boot"),
-                        value: config.onboot,
-                        defaultValue: false,
-                        pending: config.getPending('onboot'),
-                        onChanged: (v) =>
-                            bloc.events.add(UpdateQemuConfigBool('onboot', v)),
-                        onDeleted: () =>
-                            bloc.events.add(RevertPendingQemuConfig('onboot')),
-                      ),
-                      ListTile(
-                        title: Text("Start/Shutdown order"),
-                        subtitle: Text(config.startup ?? "Default (any)"),
-                      ),
-                      ListTile(
-                        title: Text("OS Type"),
-                        subtitle: Text(
-                            "${config.ostype!.type} ${config.ostype!.description}"),
-                      ),
-                      //TODO add better ui component e.g. collapseable
-                      ListTile(
-                        title: Text("Boot Device"),
-                        subtitle: Text(config.boot ?? 'Disk, Network, USB'),
-                      ),
-                      PveConfigSwitchListTile(
-                        title: Text("Use tablet for pointer"),
-                        value: config.tablet,
-                        defaultValue: true,
-                        pending: config.getPending('tablet'),
-                        onChanged: (v) =>
-                            bloc.events.add(UpdateQemuConfigBool('tablet', v)),
-                        onDeleted: () =>
-                            bloc.events.add(RevertPendingQemuConfig('tablet')),
-                      ),
-                      ListTile(
-                        title: Text("Hotplug"),
-                        subtitle: Text(config.hotplug ?? 'disk,network,usb'),
-                      ),
-                      PveConfigSwitchListTile(
-                        title: Text("ACPI support"),
-                        value: config.acpi,
-                        defaultValue: true,
-                        pending: config.getPending('acpi'),
-                        onChanged: (v) =>
-                            bloc.events.add(UpdateQemuConfigBool('acpi', v)),
-                        onDeleted: () =>
-                            bloc.events.add(RevertPendingQemuConfig('acpi')),
-                      ),
-                      PveConfigSwitchListTile(
-                        title: Text("KVM hardware virtualization"),
-                        value: config.kvm,
-                        defaultValue: true,
-                        pending: config.getPending('kvm'),
-                        onChanged: (v) =>
-                            bloc.events.add(UpdateQemuConfigBool('kvm', v)),
-                        onDeleted: () =>
-                            bloc.events.add(RevertPendingQemuConfig('kvm')),
-                      ),
-                      PveConfigSwitchListTile(
-                        title: Text("Freeze CPU on startup"),
-                        value: config.freeze,
-                        defaultValue: false,
-                        pending: config.getPending('freeze'),
-                        onChanged: (v) =>
-                            bloc.events.add(UpdateQemuConfigBool('freeze', v)),
-                        onDeleted: () =>
-                            bloc.events.add(RevertPendingQemuConfig('freeze')),
-                      ),
-                      PveConfigSwitchListTile(
-                        title: Text("Use local time for RTC"),
-                        value: config.localtime,
-                        defaultValue: false,
-                        pending: config.getPending('localtime'),
-                        onChanged: (v) => bloc.events
-                            .add(UpdateQemuConfigBool('localtime', v)),
-                        onDeleted: () => bloc.events
-                            .add(RevertPendingQemuConfig('localtime')),
-                      ),
-                      ListTile(
-                        title: Text("RTC start date"),
-                        subtitle: Text(config.startdate ?? 'now'),
-                      ),
-                      ListTile(
-                        title: Text("SMBIOS settings (type1)"),
-                        subtitle: Text(config.smbios1 ?? ''),
-                      ),
-                      //Todo enhance UI
-                      ListTile(
-                        title: Text("QEMU Guest Agent"),
-                        subtitle: Text(config.agent ?? 'Default (disabled)'),
-                      ),
-                      PveConfigSwitchListTile(
-                        title: Text("Protection"),
-                        value: config.protection,
-                        defaultValue: false,
-                        pending: config.getPending('protection'),
-                        onChanged: (v) => bloc.events
-                            .add(UpdateQemuConfigBool('protection', v)),
-                        onDeleted: () => bloc.events
-                            .add(RevertPendingQemuConfig('protection')),
-                      ),
-                      ListTile(
-                        title: Text("Spice Enhancements"),
-                        subtitle:
-                            Text(config.spiceEnhancements ?? 'No enhancements'),
-                      ),
-                      ListTile(
-                        title: Text("VM State Storage"),
-                        subtitle: Text(config.vmstatestorage ?? 'Automatic'),
-                      ),
-                    ],
+                body: SingleChildScrollView(
+                  child: Form(
+                    key: _formKey,
+                    onChanged: () {},
+                    child: Column(
+                      children: <Widget>[
+                        ListTile(
+                          title: Text("Name"),
+                          subtitle: Text(config.name ?? 'VM$guestID'),
+                        ),
+                        PveConfigSwitchListTile(
+                          title: Text("Start on boot"),
+                          value: config.onboot,
+                          defaultValue: false,
+                          pending: config.getPending('onboot'),
+                          onChanged: (v) => bloc.events
+                              .add(UpdateQemuConfigBool('onboot', v)),
+                          onDeleted: () => bloc.events
+                              .add(RevertPendingQemuConfig('onboot')),
+                        ),
+                        ListTile(
+                          title: Text("Start/Shutdown order"),
+                          subtitle: Text(config.startup ?? "Default (any)"),
+                        ),
+                        ListTile(
+                          title: Text("OS Type"),
+                          subtitle: Text(
+                              "${config.ostype!.type} ${config.ostype!.description}"),
+                        ),
+                        //TODO add better ui component e.g. collapseable
+                        ListTile(
+                          title: Text("Boot Device"),
+                          subtitle: Text(config.boot ?? 'Disk, Network, USB'),
+                        ),
+                        PveConfigSwitchListTile(
+                          title: Text("Use tablet for pointer"),
+                          value: config.tablet,
+                          defaultValue: true,
+                          pending: config.getPending('tablet'),
+                          onChanged: (v) => bloc.events
+                              .add(UpdateQemuConfigBool('tablet', v)),
+                          onDeleted: () => bloc.events
+                              .add(RevertPendingQemuConfig('tablet')),
+                        ),
+                        ListTile(
+                          title: Text("Hotplug"),
+                          subtitle: Text(config.hotplug ?? 'disk,network,usb'),
+                        ),
+                        PveConfigSwitchListTile(
+                          title: Text("ACPI support"),
+                          value: config.acpi,
+                          defaultValue: true,
+                          pending: config.getPending('acpi'),
+                          onChanged: (v) =>
+                              bloc.events.add(UpdateQemuConfigBool('acpi', v)),
+                          onDeleted: () =>
+                              bloc.events.add(RevertPendingQemuConfig('acpi')),
+                        ),
+                        PveConfigSwitchListTile(
+                          title: Text("KVM hardware virtualization"),
+                          value: config.kvm,
+                          defaultValue: true,
+                          pending: config.getPending('kvm'),
+                          onChanged: (v) =>
+                              bloc.events.add(UpdateQemuConfigBool('kvm', v)),
+                          onDeleted: () =>
+                              bloc.events.add(RevertPendingQemuConfig('kvm')),
+                        ),
+                        PveConfigSwitchListTile(
+                          title: Text("Freeze CPU on startup"),
+                          value: config.freeze,
+                          defaultValue: false,
+                          pending: config.getPending('freeze'),
+                          onChanged: (v) => bloc.events
+                              .add(UpdateQemuConfigBool('freeze', v)),
+                          onDeleted: () => bloc.events
+                              .add(RevertPendingQemuConfig('freeze')),
+                        ),
+                        PveConfigSwitchListTile(
+                          title: Text("Use local time for RTC"),
+                          value: config.localtime,
+                          defaultValue: false,
+                          pending: config.getPending('localtime'),
+                          onChanged: (v) => bloc.events
+                              .add(UpdateQemuConfigBool('localtime', v)),
+                          onDeleted: () => bloc.events
+                              .add(RevertPendingQemuConfig('localtime')),
+                        ),
+                        ListTile(
+                          title: Text("RTC start date"),
+                          subtitle: Text(config.startdate ?? 'now'),
+                        ),
+                        ListTile(
+                          title: Text("SMBIOS settings (type1)"),
+                          subtitle: Text(config.smbios1 ?? ''),
+                        ),
+                        //Todo enhance UI
+                        ListTile(
+                          title: Text("QEMU Guest Agent"),
+                          subtitle: Text(config.agent ?? 'Default (disabled)'),
+                        ),
+                        PveConfigSwitchListTile(
+                          title: Text("Protection"),
+                          value: config.protection,
+                          defaultValue: false,
+                          pending: config.getPending('protection'),
+                          onChanged: (v) => bloc.events
+                              .add(UpdateQemuConfigBool('protection', v)),
+                          onDeleted: () => bloc.events
+                              .add(RevertPendingQemuConfig('protection')),
+                        ),
+                        ListTile(
+                          title: Text("Spice Enhancements"),
+                          subtitle: Text(
+                              config.spiceEnhancements ?? 'No enhancements'),
+                        ),
+                        ListTile(
+                          title: Text("VM State Storage"),
+                          subtitle: Text(config.vmstatestorage ?? 'Automatic'),
+                        ),
+                      ],
+                    ),
                   ),
                 ),
               ),
diff --git a/lib/widgets/pve_qemu_overview.dart b/lib/widgets/pve_qemu_overview.dart
index df8867e..45f3f66 100644
--- a/lib/widgets/pve_qemu_overview.dart
+++ b/lib/widgets/pve_qemu_overview.dart
@@ -70,181 +70,184 @@ class PveQemuOverview extends StatelessWidget {
             final config = state.config;
             final rrdData = state.rrdData;
 
-            return Scaffold(
-                appBar: AppBar(
-                  //backgroundColor: Colors.transparent,
-                  elevation: 0,
-                  title: Text(config?.name ?? 'VM $guestID'),
-                ),
-                backgroundColor: Theme.of(context).colorScheme.background,
-                body: SingleChildScrollView(
-                    child: Column(
-                  children: <Widget>[
-                    PveGuestOverviewHeader(
-                      background: !(status?.template ?? false)
-                          ? PveGuestHeaderRRDPageView(
-                              rrdData: rrdData,
-                            )
-                          : Center(
-                              child: Text(
-                                "TEMPLATE",
-                                style: TextStyle(
-                                  color: Colors.white,
-                                ),
-                              ),
-                            ),
-                      width: width,
-                      guestID: guestID,
-                      guestStatus: status?.getQemuStatus(),
-                      guestName: config?.name ?? 'VM $guestID',
-                      guestNodeID: state.nodeID,
-                      guestType: 'qemu',
-                      ha: status?.ha,
-                      template: status?.template ?? false,
-                    ),
-                    ProxmoxStreamBuilder<PveTaskLogBloc, PveTaskLogState>(
-                      bloc: taskBloc,
-                      builder: (context, taskState) {
-                        if (taskState.tasks != null &&
-                            taskState.tasks.isNotEmpty) {
-                          return PveTaskExpansionTile(
-                            headerColor:
-                                Theme.of(context).colorScheme.onBackground,
-                            task: taskState.tasks.first,
-                            showMorePage: Provider<PveTaskLogBloc>(
-                              create: (context) => PveTaskLogBloc(
-                                apiClient: taskBloc.apiClient,
-                                init: PveTaskLogState.init(state.nodeID),
+            return SafeArea(
+              child: Scaffold(
+                  appBar: AppBar(
+                    //backgroundColor: Colors.transparent,
+                    elevation: 0,
+                    title: Text(config?.name ?? 'VM $guestID'),
+                  ),
+                  backgroundColor: Theme.of(context).colorScheme.background,
+                  body: SingleChildScrollView(
+                      child: Column(
+                    children: <Widget>[
+                      PveGuestOverviewHeader(
+                        background: !(status?.template ?? false)
+                            ? PveGuestHeaderRRDPageView(
+                                rrdData: rrdData,
                               )
-                                ..events.add(
-                                  FilterTasksByGuestID(
-                                    guestID: guestID,
+                            : Center(
+                                child: Text(
+                                  "TEMPLATE",
+                                  style: TextStyle(
+                                    color: Colors.white,
                                   ),
+                                ),
+                              ),
+                        width: width,
+                        guestID: guestID,
+                        guestStatus: status?.getQemuStatus(),
+                        guestName: config?.name ?? 'VM $guestID',
+                        guestNodeID: state.nodeID,
+                        guestType: 'qemu',
+                        ha: status?.ha,
+                        template: status?.template ?? false,
+                      ),
+                      ProxmoxStreamBuilder<PveTaskLogBloc, PveTaskLogState>(
+                        bloc: taskBloc,
+                        builder: (context, taskState) {
+                          if (taskState.tasks != null &&
+                              taskState.tasks.isNotEmpty) {
+                            return PveTaskExpansionTile(
+                              headerColor:
+                                  Theme.of(context).colorScheme.onBackground,
+                              task: taskState.tasks.first,
+                              showMorePage: Provider<PveTaskLogBloc>(
+                                create: (context) => PveTaskLogBloc(
+                                  apiClient: taskBloc.apiClient,
+                                  init: PveTaskLogState.init(state.nodeID),
                                 )
-                                ..events.add(LoadTasks()),
-                              dispose: (context, bloc) => bloc.dispose(),
-                              child: PveTaskLog(),
-                            ),
-                          );
-                        }
-                        return Container();
-                      },
-                    ),
-                    Container(
-                      height: 130,
-                      child: SingleChildScrollView(
-                        scrollDirection: Axis.horizontal,
-                        child: Row(
-                          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
-                          children: <Widget>[
-                            if (!(status?.template ?? false))
-                              createActionCard(
-                                  'Power Settings',
-                                  Icons.power_settings_new,
-                                  () =>
-                                      showPowerMenuBottomSheet(context, bloc)),
-                            if (!(status?.template ?? false))
+                                  ..events.add(
+                                    FilterTasksByGuestID(
+                                      guestID: guestID,
+                                    ),
+                                  )
+                                  ..events.add(LoadTasks()),
+                                dispose: (context, bloc) => bloc.dispose(),
+                                child: PveTaskLog(),
+                              ),
+                            );
+                          }
+                          return Container();
+                        },
+                      ),
+                      Container(
+                        height: 130,
+                        child: SingleChildScrollView(
+                          scrollDirection: Axis.horizontal,
+                          child: Row(
+                            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+                            children: <Widget>[
+                              if (!(status?.template ?? false))
+                                createActionCard(
+                                    'Power Settings',
+                                    Icons.power_settings_new,
+                                    () => showPowerMenuBottomSheet(
+                                        context, bloc)),
+                              if (!(status?.template ?? false))
+                                createActionCard(
+                                    'Console',
+                                    Icons.queue_play_next,
+                                    () => showConsoleMenuBottomSheet(
+                                          context,
+                                          bloc.apiClient,
+                                          guestID,
+                                          state.nodeID,
+                                          'qemu',
+                                          allowSpice: status?.spice ?? false,
+                                        )),
                               createActionCard(
-                                  'Console',
-                                  Icons.queue_play_next,
-                                  () => showConsoleMenuBottomSheet(
-                                        context,
-                                        bloc.apiClient,
-                                        guestID,
-                                        state.nodeID,
-                                        'qemu',
-                                        allowSpice: status?.spice ?? false,
-                                      )),
-                            createActionCard(
-                                'Options',
-                                Icons.settings,
-                                () => Navigator.of(context)
-                                    .push(_createOptionsRoute(bloc))),
-                            if (!rBloc.latestState.isStandalone)
+                                  'Options',
+                                  Icons.settings,
+                                  () => Navigator.of(context)
+                                      .push(_createOptionsRoute(bloc))),
+                              if (!rBloc.latestState.isStandalone)
+                                createActionCard(
+                                    'Migrate',
+                                    FontAwesomeIcons.paperPlane,
+                                    () => Navigator.of(context).push(
+                                        _createMigrationRoute(guestID,
+                                            state.nodeID, bloc.apiClient))),
                               createActionCard(
-                                  'Migrate',
-                                  FontAwesomeIcons.paperPlane,
+                                  'Backup',
+                                  FontAwesomeIcons.save,
                                   () => Navigator.of(context).push(
-                                      _createMigrationRoute(guestID,
-                                          state.nodeID, bloc.apiClient))),
-                            createActionCard(
-                                'Backup',
-                                FontAwesomeIcons.save,
-                                () => Navigator.of(context).push(
-                                    _createBackupRoute(guestID, state.nodeID,
-                                        bloc.apiClient))),
-                          ],
+                                      _createBackupRoute(guestID, state.nodeID,
+                                          bloc.apiClient))),
+                            ],
+                          ),
                         ),
                       ),
-                    ),
-                    if (config != null)
-                      PveResourceDataCardWidget(
-                          expandable: false,
-                          title: Text(
-                            'Hardware',
-                            style: TextStyle(
-                              fontWeight: FontWeight.bold,
-                              fontSize: 20,
-                            ),
-                          ),
-                          children: [
-                            ListTile(
-                              leading: Icon(FontAwesomeIcons.memory),
-                              title: Text('${config.memory}'),
-                              subtitle: Text('Memory'),
-                              dense: true,
-                            ),
-                            ListTile(
-                              leading: Icon(Icons.memory),
-                              title: Text(
-                                  '${config.cores} Cores ${config.sockets} Socket'),
-                              subtitle: Text('Processor'),
-                              dense: true,
-                            ),
-                            ListTile(
-                              leading: Icon(FontAwesomeIcons.microchip),
-                              title: Text(
-                                  config.bios?.name ?? 'Default (SeaBIOS)'),
-                              subtitle: Text('BIOS'),
-                              dense: true,
-                            ),
-                            ListTile(
-                              leading: Icon(FontAwesomeIcons.cogs),
-                              dense: true,
-                              title: Text(config.machine ?? 'Default (i440fx)'),
-                              subtitle: Text('Machine Type'),
-                            ),
-                            ListTile(
-                              leading: Icon(FontAwesomeIcons.database),
-                              title: Text(
-                                  config.scsihw?.name ?? 'Default (i440fx)'),
-                              subtitle: Text('SCSI Controller'),
-                              dense: true,
+                      if (config != null)
+                        PveResourceDataCardWidget(
+                            expandable: false,
+                            title: Text(
+                              'Hardware',
+                              style: TextStyle(
+                                fontWeight: FontWeight.bold,
+                                fontSize: 20,
+                              ),
                             ),
-                            for (var ide in config.ide!)
+                            children: [
                               ListTile(
-                                leading: Icon(FontAwesomeIcons.compactDisc),
-                                title: Text(ide),
-                                subtitle: Text('CD/DVD Drive'),
+                                leading: Icon(FontAwesomeIcons.memory),
+                                title: Text('${config.memory}'),
+                                subtitle: Text('Memory'),
                                 dense: true,
                               ),
-                            for (var scsi in config.scsi!)
                               ListTile(
-                                leading: Icon(FontAwesomeIcons.hdd),
-                                title: Text(scsi),
-                                subtitle: Text('Hard Disk'),
+                                leading: Icon(Icons.memory),
+                                title: Text(
+                                    '${config.cores} Cores ${config.sockets} Socket'),
+                                subtitle: Text('Processor'),
                                 dense: true,
                               ),
-                            for (var net in config.net!)
                               ListTile(
-                                leading: Icon(FontAwesomeIcons.ethernet),
+                                leading: Icon(FontAwesomeIcons.microchip),
+                                title: Text(
+                                    config.bios?.name ?? 'Default (SeaBIOS)'),
+                                subtitle: Text('BIOS'),
                                 dense: true,
-                                subtitle: Text('Network Device'),
-                                title: Text(net),
-                              )
-                          ]),
-                  ],
-                )));
+                              ),
+                              ListTile(
+                                leading: Icon(FontAwesomeIcons.cogs),
+                                dense: true,
+                                title:
+                                    Text(config.machine ?? 'Default (i440fx)'),
+                                subtitle: Text('Machine Type'),
+                              ),
+                              ListTile(
+                                leading: Icon(FontAwesomeIcons.database),
+                                title: Text(
+                                    config.scsihw?.name ?? 'Default (i440fx)'),
+                                subtitle: Text('SCSI Controller'),
+                                dense: true,
+                              ),
+                              for (var ide in config.ide!)
+                                ListTile(
+                                  leading: Icon(FontAwesomeIcons.compactDisc),
+                                  title: Text(ide),
+                                  subtitle: Text('CD/DVD Drive'),
+                                  dense: true,
+                                ),
+                              for (var scsi in config.scsi!)
+                                ListTile(
+                                  leading: Icon(FontAwesomeIcons.hdd),
+                                  title: Text(scsi),
+                                  subtitle: Text('Hard Disk'),
+                                  dense: true,
+                                ),
+                              for (var net in config.net!)
+                                ListTile(
+                                  leading: Icon(FontAwesomeIcons.ethernet),
+                                  dense: true,
+                                  subtitle: Text('Network Device'),
+                                  title: Text(net),
+                                )
+                            ]),
+                    ],
+                  ))),
+            );
           }),
     );
   }
diff --git a/lib/widgets/pve_qemu_power_settings_widget.dart b/lib/widgets/pve_qemu_power_settings_widget.dart
index 2d4c496..46c07cc 100644
--- a/lib/widgets/pve_qemu_power_settings_widget.dart
+++ b/lib/widgets/pve_qemu_power_settings_widget.dart
@@ -18,103 +18,105 @@ class PveQemuPowerSettings extends StatelessWidget {
         builder: (context, state) {
           final qemuStatus = state.currentStatus?.getQemuStatus();
           final disableShutdown = qemuStatus != PveResourceStatusType.running;
-          return SingleChildScrollView(
-            child: Container(
-              constraints: BoxConstraints(
-                  minHeight: MediaQuery.of(context).size.height / 3),
-              child: Column(
-                mainAxisSize: MainAxisSize.min,
-                children: <Widget>[
-                  if (qemuStatus == PveResourceStatusType.stopped &&
-                      !(state.currentStatus!.template ?? false))
-                    ListTile(
-                      leading: Icon(Icons.play_arrow),
-                      title: Text(
-                        "Start",
-                        style: TextStyle(fontWeight: FontWeight.bold),
+          return SafeArea(
+            child: SingleChildScrollView(
+              child: Container(
+                constraints: BoxConstraints(
+                    minHeight: MediaQuery.of(context).size.height / 3),
+                child: Column(
+                  mainAxisSize: MainAxisSize.min,
+                  children: <Widget>[
+                    if (qemuStatus == PveResourceStatusType.stopped &&
+                        !(state.currentStatus!.template ?? false))
+                      ListTile(
+                        leading: Icon(Icons.play_arrow),
+                        title: Text(
+                          "Start",
+                          style: TextStyle(fontWeight: FontWeight.bold),
+                        ),
+                        subtitle: Text("Turn on QEMU virtual machine"),
+                        onTap: () => action(
+                            context, PveClusterResourceAction.start, bloc),
                       ),
-                      subtitle: Text("Turn on QEMU virtual machine"),
-                      onTap: () =>
-                          action(context, PveClusterResourceAction.start, bloc),
-                    ),
-                  if ([
-                        PveResourceStatusType.paused,
-                        PveResourceStatusType.suspended
-                      ].contains(qemuStatus) &&
-                      !(state.currentStatus!.template ?? false))
-                    ListTile(
-                      leading: Icon(Icons.play_arrow),
-                      title: Text(
-                        "Resume",
-                        style: TextStyle(fontWeight: FontWeight.bold),
+                    if ([
+                          PveResourceStatusType.paused,
+                          PveResourceStatusType.suspended
+                        ].contains(qemuStatus) &&
+                        !(state.currentStatus!.template ?? false))
+                      ListTile(
+                        leading: Icon(Icons.play_arrow),
+                        title: Text(
+                          "Resume",
+                          style: TextStyle(fontWeight: FontWeight.bold),
+                        ),
+                        subtitle: Text("Resume QEMU virtual machine"),
+                        onTap: () => action(
+                            context, PveClusterResourceAction.resume, bloc),
                       ),
-                      subtitle: Text("Resume QEMU virtual machine"),
-                      onTap: () => action(
-                          context, PveClusterResourceAction.resume, bloc),
-                    ),
-                  if (!disableShutdown) ...[
-                    ListTile(
-                      leading: Icon(Icons.power_settings_new),
-                      title: Text(
-                        "Shutdown",
-                        style: TextStyle(fontWeight: FontWeight.bold),
+                    if (!disableShutdown) ...[
+                      ListTile(
+                        leading: Icon(Icons.power_settings_new),
+                        title: Text(
+                          "Shutdown",
+                          style: TextStyle(fontWeight: FontWeight.bold),
+                        ),
+                        subtitle: Text("Shutdown QEMU virtual machine"),
+                        onTap: () => action(
+                            context, PveClusterResourceAction.shutdown, bloc),
                       ),
-                      subtitle: Text("Shutdown QEMU virtual machine"),
-                      onTap: () => action(
-                          context, PveClusterResourceAction.shutdown, bloc),
-                    ),
-                    ListTile(
-                      leading: Icon(Icons.autorenew),
-                      title: Text(
-                        "Reboot",
-                        style: TextStyle(fontWeight: FontWeight.bold),
+                      ListTile(
+                        leading: Icon(Icons.autorenew),
+                        title: Text(
+                          "Reboot",
+                          style: TextStyle(fontWeight: FontWeight.bold),
+                        ),
+                        subtitle: Text("Reboot QEMU virtual machine"),
+                        onTap: () => action(
+                            context, PveClusterResourceAction.reboot, bloc),
                       ),
-                      subtitle: Text("Reboot QEMU virtual machine"),
-                      onTap: () => action(
-                          context, PveClusterResourceAction.reboot, bloc),
-                    ),
-                    ListTile(
-                      leading: Icon(Icons.pause),
-                      title: Text(
-                        "Pause",
-                        style: TextStyle(fontWeight: FontWeight.bold),
+                      ListTile(
+                        leading: Icon(Icons.pause),
+                        title: Text(
+                          "Pause",
+                          style: TextStyle(fontWeight: FontWeight.bold),
+                        ),
+                        subtitle: Text("Pause QEMU virtual machine"),
+                        onTap: () => action(
+                            context, PveClusterResourceAction.suspend, bloc),
                       ),
-                      subtitle: Text("Pause QEMU virtual machine"),
-                      onTap: () => action(
-                          context, PveClusterResourceAction.suspend, bloc),
-                    ),
-                    ListTile(
-                      leading: Icon(FontAwesomeIcons.download),
-                      title: Text(
-                        "Hibernate",
-                        style: TextStyle(fontWeight: FontWeight.bold),
+                      ListTile(
+                        leading: Icon(FontAwesomeIcons.download),
+                        title: Text(
+                          "Hibernate",
+                          style: TextStyle(fontWeight: FontWeight.bold),
+                        ),
+                        subtitle: Text("Hibernate QEMU virtual machine"),
+                        onTap: () => action(
+                            context, PveClusterResourceAction.hibernate, bloc),
                       ),
-                      subtitle: Text("Hibernate QEMU virtual machine"),
-                      onTap: () => action(
-                          context, PveClusterResourceAction.hibernate, bloc),
-                    ),
-                    ListTile(
-                      leading: Icon(Icons.stop),
-                      title: Text(
-                        "Stop",
-                        style: TextStyle(fontWeight: FontWeight.bold),
+                      ListTile(
+                        leading: Icon(Icons.stop),
+                        title: Text(
+                          "Stop",
+                          style: TextStyle(fontWeight: FontWeight.bold),
+                        ),
+                        subtitle: Text("Stop QEMU virtual machine"),
+                        onTap: () => action(
+                            context, PveClusterResourceAction.stop, bloc),
                       ),
-                      subtitle: Text("Stop QEMU virtual machine"),
-                      onTap: () =>
-                          action(context, PveClusterResourceAction.stop, bloc),
-                    ),
-                    ListTile(
-                      leading: Icon(FontAwesomeIcons.bolt),
-                      title: Text(
-                        "Reset",
-                        style: TextStyle(fontWeight: FontWeight.bold),
+                      ListTile(
+                        leading: Icon(FontAwesomeIcons.bolt),
+                        title: Text(
+                          "Reset",
+                          style: TextStyle(fontWeight: FontWeight.bold),
+                        ),
+                        subtitle: Text("Reset QEMU virtual machine"),
+                        onTap: () => action(
+                            context, PveClusterResourceAction.reset, bloc),
                       ),
-                      subtitle: Text("Reset QEMU virtual machine"),
-                      onTap: () =>
-                          action(context, PveClusterResourceAction.reset, bloc),
-                    ),
+                    ],
                   ],
-                ],
+                ),
               ),
             ),
           );
-- 
2.30.2






More information about the pve-devel mailing list