* [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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.