public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
* [pve-devel] [PATCH login_manager, flutter_frontend 0/2] Avoid elements hiding behind Android soft nav buttons
@ 2021-12-27 14:07 Aaron Lauterer
  2021-12-27 14:07 ` [pve-devel] [PATCH login_manager 1/2] login_form: keep Continue button above Android softnav Aaron Lauterer
  2021-12-27 14:07 ` [pve-devel] [PATCH flutter_frontend 2/2] avoid elements hiding behind Android softnav buttons Aaron Lauterer
  0 siblings, 2 replies; 3+ messages in thread
From: Aaron Lauterer @ 2021-12-27 14:07 UTC (permalink / raw)
  To: pve-devel

In a few places we had the situation, that elements would get hidden
behind the Android soft nav buttons at the bottom of the screen. Placing
them inside a SafeArea element avoids this.

These instances are:
* Continue button in the Login manager when adding a new site
* Qemu HW overview list
* Qemu Power Control menu
* LXC and Qemu Options list

Unfortunately, the resulting diff is quite big since all child elements
were indented one level more.


login_manager: Aaron Lauterer (1):
  login_form: keep Continue button above Android softnav

 lib/proxmox_login_form.dart | 265 ++++++++++++++++++------------------
 1 file changed, 135 insertions(+), 130 deletions(-)


flutter_frontend: Aaron Lauterer (1):
  avoid elements hiding behind Android softnav buttons

 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(-)


-- 
2.30.2





^ permalink raw reply	[flat|nested] 3+ messages in thread

* [pve-devel] [PATCH login_manager 1/2] login_form: keep Continue button above Android softnav
  2021-12-27 14:07 [pve-devel] [PATCH login_manager, flutter_frontend 0/2] Avoid elements hiding behind Android soft nav buttons Aaron Lauterer
@ 2021-12-27 14:07 ` Aaron Lauterer
  2021-12-27 14:07 ` [pve-devel] [PATCH flutter_frontend 2/2] avoid elements hiding behind Android softnav buttons Aaron Lauterer
  1 sibling, 0 replies; 3+ messages in thread
From: Aaron Lauterer @ 2021-12-27 14:07 UTC (permalink / raw)
  To: pve-devel

By placing the items in a SafeArea we avoid having the "Continue" button
behind the Android soft navigation buttons.

Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com>
---
 lib/proxmox_login_form.dart | 265 ++++++++++++++++++------------------
 1 file changed, 135 insertions(+), 130 deletions(-)

diff --git a/lib/proxmox_login_form.dart b/lib/proxmox_login_form.dart
index 2609f71..bb00b5c 100644
--- a/lib/proxmox_login_form.dart
+++ b/lib/proxmox_login_form.dart
@@ -232,152 +232,157 @@ class _ProxmoxLoginPageState extends State<ProxmoxLoginPage> {
               child: ConstrainedBox(
                 constraints: BoxConstraints.tightFor(
                     height: MediaQuery.of(context).size.height),
-                child: Padding(
-                  padding: const EdgeInsets.all(8.0),
-                  child: FutureBuilder<List<PveAccessDomainModel?>?>(
-                      future: _accessDomains,
-                      builder: (context, snapshot) {
-                        return Form(
-                          key: _formKey,
-                          onChanged: () {
-                            setState(() {
-                              _submittButtonEnabled =
-                                  _formKey.currentState!.validate();
-                            });
-                          },
-                          child: Column(
-                            mainAxisAlignment: MainAxisAlignment.center,
-                            children: [
-                              Expanded(
-                                child: Container(
-                                  child: Column(
-                                    mainAxisAlignment: MainAxisAlignment.center,
-                                    children: [
-                                      Image.asset(
-                                        'assets/images/proxmox_logo_symbol_wordmark.png',
-                                        package: 'proxmox_login_manager',
-                                      ),
-                                    ],
+                child: SafeArea(
+                  child: Padding(
+                    padding: const EdgeInsets.all(8.0),
+                    child: FutureBuilder<List<PveAccessDomainModel?>?>(
+                        future: _accessDomains,
+                        builder: (context, snapshot) {
+                          return Form(
+                            key: _formKey,
+                            onChanged: () {
+                              setState(() {
+                                _submittButtonEnabled =
+                                    _formKey.currentState!.validate();
+                              });
+                            },
+                            child: Column(
+                              mainAxisAlignment: MainAxisAlignment.center,
+                              children: [
+                                Expanded(
+                                  child: Container(
+                                    child: Column(
+                                      mainAxisAlignment:
+                                          MainAxisAlignment.center,
+                                      children: [
+                                        Image.asset(
+                                          'assets/images/proxmox_logo_symbol_wordmark.png',
+                                          package: 'proxmox_login_manager',
+                                        ),
+                                      ],
+                                    ),
                                   ),
                                 ),
-                              ),
-                              ProxmoxLoginForm(
-                                originController: _originController,
-                                originValidator: (value) {
-                                  if (value == null || value.isEmpty) {
-                                    return 'Please enter origin';
-                                  }
-                                  if (value.startsWith('https://') ||
-                                      value.startsWith('http://')) {
-                                    return 'Do not prefix with scheme';
-                                  }
-                                  try {
-                                    Uri.https(value, '');
-                                    return null;
-                                  } on FormatException catch (_) {
-                                    return 'Invalid URI';
-                                  }
-                                },
-                                usernameController: _usernameController,
-                                passwordController: _passwordController,
-                                accessDomains: snapshot.data,
-                                selectedDomain: _selectedDomain,
-                                onDomainChanged: (value) {
-                                  setState(() {
-                                    _selectedDomain = value;
-                                  });
-                                },
-                                onOriginSubmitted: _submittButtonEnabled
-                                    ? () {
-                                        final isValid =
-                                            _formKey.currentState!.validate();
-                                        setState(() {
-                                          _submittButtonEnabled = isValid;
-                                        });
-                                        if (isValid) {
+                                ProxmoxLoginForm(
+                                  originController: _originController,
+                                  originValidator: (value) {
+                                    if (value == null || value.isEmpty) {
+                                      return 'Please enter origin';
+                                    }
+                                    if (value.startsWith('https://') ||
+                                        value.startsWith('http://')) {
+                                      return 'Do not prefix with scheme';
+                                    }
+                                    try {
+                                      Uri.https(value, '');
+                                      return null;
+                                    } on FormatException catch (_) {
+                                      return 'Invalid URI';
+                                    }
+                                  },
+                                  usernameController: _usernameController,
+                                  passwordController: _passwordController,
+                                  accessDomains: snapshot.data,
+                                  selectedDomain: _selectedDomain,
+                                  onDomainChanged: (value) {
+                                    setState(() {
+                                      _selectedDomain = value;
+                                    });
+                                  },
+                                  onOriginSubmitted: _submittButtonEnabled
+                                      ? () {
+                                          final isValid =
+                                              _formKey.currentState!.validate();
                                           setState(() {
-                                            _accessDomains =
-                                                _getAccessDomains();
+                                            _submittButtonEnabled = isValid;
                                           });
+                                          if (isValid) {
+                                            setState(() {
+                                              _accessDomains =
+                                                  _getAccessDomains();
+                                            });
+                                          }
                                         }
-                                      }
-                                    : null,
-                                onPasswordSubmitted: _submittButtonEnabled
-                                    ? () {
-                                        final isValid =
-                                            _formKey.currentState!.validate();
-                                        setState(() {
-                                          _submittButtonEnabled = isValid;
-                                        });
-                                        if (isValid) {
-                                          _onLoginButtonPressed();
+                                      : null,
+                                  onPasswordSubmitted: _submittButtonEnabled
+                                      ? () {
+                                          final isValid =
+                                              _formKey.currentState!.validate();
+                                          setState(() {
+                                            _submittButtonEnabled = isValid;
+                                          });
+                                          if (isValid) {
+                                            _onLoginButtonPressed();
+                                          }
                                         }
-                                      }
-                                    : null,
-                              ),
-                              if (snapshot.hasData)
-                                Expanded(
-                                  child: Align(
-                                    alignment: Alignment.bottomCenter,
-                                    child: Container(
-                                      width: MediaQuery.of(context).size.width,
-                                      child: FlatButton(
-                                        onPressed: _submittButtonEnabled
-                                            ? () {
-                                                final isValid = _formKey
-                                                    .currentState!
-                                                    .validate();
-                                                setState(() {
-                                                  _submittButtonEnabled =
-                                                      isValid;
-                                                });
-                                                if (isValid) {
-                                                  _onLoginButtonPressed();
+                                      : null,
+                                ),
+                                if (snapshot.hasData)
+                                  Expanded(
+                                    child: Align(
+                                      alignment: Alignment.bottomCenter,
+                                      child: Container(
+                                        width:
+                                            MediaQuery.of(context).size.width,
+                                        child: FlatButton(
+                                          onPressed: _submittButtonEnabled
+                                              ? () {
+                                                  final isValid = _formKey
+                                                      .currentState!
+                                                      .validate();
+                                                  setState(() {
+                                                    _submittButtonEnabled =
+                                                        isValid;
+                                                  });
+                                                  if (isValid) {
+                                                    _onLoginButtonPressed();
+                                                  }
                                                 }
-                                              }
-                                            : null,
-                                        color: ProxmoxColors.orange,
-                                        disabledColor: Colors.grey,
-                                        child: Text('Continue'),
+                                              : null,
+                                          color: ProxmoxColors.orange,
+                                          disabledColor: Colors.grey,
+                                          child: Text('Continue'),
+                                        ),
                                       ),
                                     ),
                                   ),
-                                ),
-                              if (!snapshot.hasData)
-                                Expanded(
-                                  child: Align(
-                                    alignment: Alignment.bottomCenter,
-                                    child: Container(
-                                      width: MediaQuery.of(context).size.width,
-                                      child: FlatButton(
-                                        onPressed: _submittButtonEnabled
-                                            ? () {
-                                                final isValid = _formKey
-                                                    .currentState!
-                                                    .validate();
-                                                setState(() {
-                                                  _submittButtonEnabled =
-                                                      isValid;
-                                                });
-                                                if (isValid) {
+                                if (!snapshot.hasData)
+                                  Expanded(
+                                    child: Align(
+                                      alignment: Alignment.bottomCenter,
+                                      child: Container(
+                                        width:
+                                            MediaQuery.of(context).size.width,
+                                        child: FlatButton(
+                                          onPressed: _submittButtonEnabled
+                                              ? () {
+                                                  final isValid = _formKey
+                                                      .currentState!
+                                                      .validate();
                                                   setState(() {
-                                                    _accessDomains =
-                                                        _getAccessDomains();
+                                                    _submittButtonEnabled =
+                                                        isValid;
                                                   });
+                                                  if (isValid) {
+                                                    setState(() {
+                                                      _accessDomains =
+                                                          _getAccessDomains();
+                                                    });
+                                                  }
                                                 }
-                                              }
-                                            : null,
-                                        color: ProxmoxColors.orange,
-                                        child: Text('Continue'),
-                                        disabledColor: Colors.grey,
+                                              : null,
+                                          color: ProxmoxColors.orange,
+                                          child: Text('Continue'),
+                                          disabledColor: Colors.grey,
+                                        ),
                                       ),
                                     ),
                                   ),
-                                ),
-                            ],
-                          ),
-                        );
-                      }),
+                              ],
+                            ),
+                          );
+                        }),
+                  ),
                 ),
               ),
             ),
-- 
2.30.2





^ permalink raw reply	[flat|nested] 3+ messages in thread

* [pve-devel] [PATCH flutter_frontend 2/2] avoid elements hiding behind Android softnav buttons
  2021-12-27 14:07 [pve-devel] [PATCH login_manager, flutter_frontend 0/2] Avoid elements hiding behind Android soft nav buttons Aaron Lauterer
  2021-12-27 14:07 ` [pve-devel] [PATCH login_manager 1/2] login_form: keep Continue button above Android softnav Aaron Lauterer
@ 2021-12-27 14:07 ` Aaron Lauterer
  1 sibling, 0 replies; 3+ messages in thread
From: Aaron Lauterer @ 2021-12-27 14:07 UTC (permalink / raw)
  To: pve-devel

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@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





^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2021-12-27 14:07 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-27 14:07 [pve-devel] [PATCH login_manager, flutter_frontend 0/2] Avoid elements hiding behind Android soft nav buttons Aaron Lauterer
2021-12-27 14:07 ` [pve-devel] [PATCH login_manager 1/2] login_form: keep Continue button above Android softnav Aaron Lauterer
2021-12-27 14:07 ` [pve-devel] [PATCH flutter_frontend 2/2] avoid elements hiding behind Android softnav buttons Aaron Lauterer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal