* [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