all lists on lists.proxmox.com
 help / color / mirror / Atom feed
From: Shan Shaji <s.shaji@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [pve-devel] [PATCH pve_flutter_frontend] fix: ui: app bar text alignment issues in iOS
Date: Thu, 15 May 2025 14:19:24 +0200	[thread overview]
Message-ID: <20250515121924.59961-1-s.shaji@proxmox.com> (raw)

By default iOS centers the title in the appbar, which can create a
visual inconsistency with the left aligned two line app name.

Added a custom `PveAppBar` widget to maintain the design and alignment
similliar to android. Also the new widget replaces all other `AppBar`
widgets that has the title property specified.

Signed-off-by: Shan Shaji <s.shaji@proxmox.com>
---
 lib/pages/main_layout_slim.dart           |  9 ++---
 lib/widgets/pve_app_bar.dart              | 47 +++++++++++++++++++++++
 lib/widgets/pve_file_selector_widget.dart |  4 +-
 lib/widgets/pve_guest_backup_widget.dart  |  7 ++--
 lib/widgets/pve_guest_migrate_widget.dart |  4 +-
 lib/widgets/pve_lxc_overview.dart         |  4 +-
 lib/widgets/pve_node_overview.dart        |  5 +--
 lib/widgets/pve_qemu_overview.dart        |  5 +--
 8 files changed, 64 insertions(+), 21 deletions(-)
 create mode 100644 lib/widgets/pve_app_bar.dart

diff --git a/lib/pages/main_layout_slim.dart b/lib/pages/main_layout_slim.dart
index ac5a6f9..5e1bfa5 100644
--- a/lib/pages/main_layout_slim.dart
+++ b/lib/pages/main_layout_slim.dart
@@ -23,6 +23,7 @@ import 'package:pve_flutter_frontend/widgets/proxmox_custom_icon.dart';
 import 'package:pve_flutter_frontend/widgets/proxmox_gauge_chart.dart';
 import 'package:pve_flutter_frontend/widgets/proxmox_heartbeat_indicator.dart';
 import 'package:pve_flutter_frontend/widgets/proxmox_stream_builder_widget.dart';
+import 'package:pve_flutter_frontend/widgets/pve_app_bar.dart';
 import 'package:pve_flutter_frontend/widgets/pve_file_selector_widget.dart';
 import 'package:pve_flutter_frontend/widgets/pve_guest_icon_widget.dart';
 import 'package:pve_flutter_frontend/widgets/pve_help_icon_button_widget.dart';
@@ -167,7 +168,7 @@ class MobileDashboard extends StatelessWidget {
     final cBloc = Provider.of<PveClusterStatusBloc>(context);
     final rBloc = Provider.of<PveResourceBloc>(context);
     return Scaffold(
-      appBar: AppBar(
+      appBar: PveAppBar(
         title: const Column(
           crossAxisAlignment: CrossAxisAlignment.start,
           children: [
@@ -185,7 +186,6 @@ class MobileDashboard extends StatelessWidget {
             )
           ],
         ),
-        elevation: 0.0,
         leading: const Icon(
           ProxmoxIcons.proxmox,
           size: 36,
@@ -607,9 +607,8 @@ class MobileResourceOverview extends StatelessWidget {
           child: ColoredSafeArea(
               child: Scaffold(
             endDrawer: _MobileResourceFilterSheet(),
-            appBar: AppBar(
+            appBar: PveAppBar(
               automaticallyImplyLeading: false,
-              elevation: 0,
               title: AppbarSearchTextField(
                 onChanged: (filter) =>
                     rBloc.events.add(FilterResources(nameFilter: filter)),
@@ -1051,7 +1050,7 @@ class MobileAccessManagement extends StatelessWidget {
     return DefaultTabController(
       length: 5,
       child: Scaffold(
-        appBar: AppBar(
+        appBar: PveAppBar(
           title: const Text('Permissions'),
           //backgroundColor: Colors.transparent,
           elevation: 0.0,
diff --git a/lib/widgets/pve_app_bar.dart b/lib/widgets/pve_app_bar.dart
new file mode 100644
index 0000000..de24b96
--- /dev/null
+++ b/lib/widgets/pve_app_bar.dart
@@ -0,0 +1,47 @@
+import 'package:flutter/material.dart';
+
+class PveAppBar extends StatelessWidget implements PreferredSizeWidget {
+  PveAppBar({
+    super.key,
+    this.title,
+    this.automaticallyImplyLeading = true,
+    this.elevation,
+    this.leading,
+    this.actions,
+    this.centerTitle,
+    this.bottom,
+    this.toolbarHeight,
+    this.backgroundColor,
+    this.iconTheme,
+  }) : preferredSize = Size.fromHeight((toolbarHeight ?? kToolbarHeight) +
+            (bottom?.preferredSize.height ?? 0));
+
+  final Widget? title;
+  final double? elevation;
+  final Widget? leading;
+  final bool automaticallyImplyLeading;
+  final List<Widget>? actions;
+  final bool? centerTitle;
+  final PreferredSizeWidget? bottom;
+  final double? toolbarHeight;
+  final Color? backgroundColor;
+  final IconThemeData? iconTheme;
+
+  @override
+  final Size preferredSize;
+
+  @override
+  Widget build(BuildContext context) {
+    return AppBar(
+      centerTitle: centerTitle ?? false,
+      title: title,
+      elevation: elevation ?? 0,
+      leading: leading,
+      automaticallyImplyLeading: automaticallyImplyLeading,
+      actions: actions,
+      bottom: bottom,
+      backgroundColor: backgroundColor,
+      iconTheme: iconTheme,
+    );
+  }
+}
diff --git a/lib/widgets/pve_file_selector_widget.dart b/lib/widgets/pve_file_selector_widget.dart
index 9770ff8..f03a021 100644
--- a/lib/widgets/pve_file_selector_widget.dart
+++ b/lib/widgets/pve_file_selector_widget.dart
@@ -11,6 +11,7 @@ import 'package:pve_flutter_frontend/utils/renderers.dart';
 import 'package:pve_flutter_frontend/widgets/proxmox_capacity_indicator.dart';
 import 'package:pve_flutter_frontend/widgets/proxmox_stream_builder_widget.dart';
 import 'package:pve_flutter_frontend/widgets/proxmox_stream_listener.dart';
+import 'package:pve_flutter_frontend/widgets/pve_app_bar.dart';
 
 class PveFileSelector extends StatefulWidget {
   final PveFileSelectorBloc? fBloc;
@@ -32,8 +33,7 @@ class _PveFileSelectorState extends State<PveFileSelector> {
   Widget build(BuildContext context) {
     return ProxmoxLayoutBuilder(
       builder: (context, layout) => Scaffold(
-        appBar: AppBar(
-          elevation: 0,
+        appBar: PveAppBar(
           title: const Text("Storage"),
         ),
         body: PveFileSelectorWidget(
diff --git a/lib/widgets/pve_guest_backup_widget.dart b/lib/widgets/pve_guest_backup_widget.dart
index 8aa7e31..7bd38d4 100644
--- a/lib/widgets/pve_guest_backup_widget.dart
+++ b/lib/widgets/pve_guest_backup_widget.dart
@@ -12,6 +12,7 @@ import 'package:pve_flutter_frontend/utils/utils.dart';
 import 'package:pve_flutter_frontend/utils/validators.dart';
 import 'package:pve_flutter_frontend/widgets/proxmox_stream_builder_widget.dart';
 import 'package:pve_flutter_frontend/widgets/proxmox_stream_listener.dart';
+import 'package:pve_flutter_frontend/widgets/pve_app_bar.dart';
 import 'package:pve_flutter_frontend/widgets/pve_file_selector_widget.dart';
 import 'package:pve_flutter_frontend/widgets/pve_storage_selector_widget.dart';
 
@@ -25,8 +26,7 @@ class PveGuestBackupWidget extends StatelessWidget {
     final sBloc = Provider.of<PveStorageSelectorBloc>(context);
     final fBloc = Provider.of<PveFileSelectorBloc>(context);
     return Scaffold(
-      appBar: AppBar(
-        elevation: 0,
+      appBar: PveAppBar(
         title: Text("Backup $guestID"),
       ),
       body: Column(
@@ -417,10 +417,9 @@ class _PveBackupFormState extends State<PveBackupForm> {
     return ScaffoldMessenger(
         key: _scaffoldKey,
         child: Scaffold(
-          appBar: AppBar(
+          appBar: PveAppBar(
             iconTheme: const IconThemeData(color: Colors.black),
             backgroundColor: Colors.transparent,
-            elevation: 0,
             title: const Text(
               "Schedule backup",
               style: TextStyle(color: Colors.black),
diff --git a/lib/widgets/pve_guest_migrate_widget.dart b/lib/widgets/pve_guest_migrate_widget.dart
index d467dd7..5ef72eb 100644
--- a/lib/widgets/pve_guest_migrate_widget.dart
+++ b/lib/widgets/pve_guest_migrate_widget.dart
@@ -8,6 +8,7 @@ import 'package:pve_flutter_frontend/bloc/pve_resource_bloc.dart';
 import 'package:pve_flutter_frontend/states/pve_migrate_state.dart';
 import 'package:pve_flutter_frontend/states/pve_node_selector_state.dart';
 import 'package:pve_flutter_frontend/widgets/proxmox_stream_builder_widget.dart';
+import 'package:pve_flutter_frontend/widgets/pve_app_bar.dart';
 import 'package:pve_flutter_frontend/widgets/pve_guest_migration_connector_widget.dart';
 import 'package:pve_flutter_frontend/widgets/pve_help_icon_button_widget.dart';
 
@@ -23,7 +24,7 @@ class PveGuestMigrate extends StatelessWidget {
       bloc: migrateBloc,
       builder: (context, migrateState) {
         return Scaffold(
-          appBar: AppBar(
+          appBar: PveAppBar(
             title: const Text(
               "Migration",
               style: TextStyle(color: Colors.white, fontSize: 25),
@@ -34,7 +35,6 @@ class PveGuestMigrate extends StatelessWidget {
               icon: const Icon(Icons.close),
               onPressed: () => Navigator.of(context).pop(),
             ),
-            elevation: 0.0,
             actions: <Widget>[
               PveHelpIconButton(
                   baseUrl: (Provider.of<PveResourceBloc>(context)
diff --git a/lib/widgets/pve_lxc_overview.dart b/lib/widgets/pve_lxc_overview.dart
index e8e6edb..2af58df 100644
--- a/lib/widgets/pve_lxc_overview.dart
+++ b/lib/widgets/pve_lxc_overview.dart
@@ -23,6 +23,7 @@ import 'package:pve_flutter_frontend/widgets/colored_safe_area.dart';
 import 'package:pve_flutter_frontend/widgets/proxmox_stream_builder_widget.dart';
 import 'package:pve_flutter_frontend/widgets/proxmox_stream_listener.dart';
 import 'package:pve_flutter_frontend/widgets/pve_action_card_widget.dart';
+import 'package:pve_flutter_frontend/widgets/pve_app_bar.dart';
 import 'package:pve_flutter_frontend/widgets/pve_guest_backup_widget.dart';
 import 'package:pve_flutter_frontend/widgets/pve_guest_migrate_widget.dart';
 import 'package:pve_flutter_frontend/widgets/pve_guest_overview_header.dart';
@@ -72,8 +73,7 @@ class PveLxcOverview extends StatelessWidget {
             final config = state.config;
             return ColoredSafeArea(
               child: Scaffold(
-                appBar: AppBar(
-                  elevation: 0,
+                appBar: PveAppBar(
                   title: Text(config?.hostname ?? 'CT $guestID'),
                 ),
                 backgroundColor: Theme.of(context).colorScheme.surfaceContainer,
diff --git a/lib/widgets/pve_node_overview.dart b/lib/widgets/pve_node_overview.dart
index 85410fb..98767fe 100644
--- a/lib/widgets/pve_node_overview.dart
+++ b/lib/widgets/pve_node_overview.dart
@@ -9,6 +9,7 @@ import 'package:pve_flutter_frontend/states/pve_task_log_state.dart';
 import 'package:pve_flutter_frontend/utils/renderers.dart';
 import 'package:pve_flutter_frontend/utils/utils.dart';
 import 'package:pve_flutter_frontend/widgets/colored_safe_area.dart';
+import 'package:pve_flutter_frontend/widgets/pve_app_bar.dart';
 import 'package:pve_flutter_frontend/widgets/pve_node_power_settings_widget.dart';
 import 'package:pve_flutter_frontend/widgets/proxmox_capacity_indicator.dart';
 import 'package:pve_flutter_frontend/widgets/proxmox_stream_builder_widget.dart';
@@ -52,9 +53,7 @@ class PveNodeOverview extends StatelessWidget {
             Theme.of(context).colorScheme.onPrimary.withValues(alpha: 0.75);
         return ColoredSafeArea(
           child: Scaffold(
-            appBar: AppBar(
-              //backgroundColor: Colors.transparent,
-              elevation: 0,
+            appBar: PveAppBar(
               title: Text(
                 "Node $nodeID",
                 style:
diff --git a/lib/widgets/pve_qemu_overview.dart b/lib/widgets/pve_qemu_overview.dart
index b019b0f..20bb648 100644
--- a/lib/widgets/pve_qemu_overview.dart
+++ b/lib/widgets/pve_qemu_overview.dart
@@ -23,6 +23,7 @@ import 'package:pve_flutter_frontend/widgets/colored_safe_area.dart';
 import 'package:pve_flutter_frontend/widgets/proxmox_stream_builder_widget.dart';
 import 'package:pve_flutter_frontend/widgets/proxmox_stream_listener.dart';
 import 'package:pve_flutter_frontend/widgets/pve_action_card_widget.dart';
+import 'package:pve_flutter_frontend/widgets/pve_app_bar.dart';
 import 'package:pve_flutter_frontend/widgets/pve_guest_backup_widget.dart';
 import 'package:pve_flutter_frontend/widgets/pve_guest_overview_header.dart';
 import 'package:pve_flutter_frontend/widgets/pve_guest_migrate_widget.dart';
@@ -73,9 +74,7 @@ class PveQemuOverview extends StatelessWidget {
 
             return ColoredSafeArea(
               child: Scaffold(
-                  appBar: AppBar(
-                    //backgroundColor: Colors.transparent,
-                    elevation: 0,
+                  appBar: PveAppBar(
                     title: Text(config?.name ?? 'VM $guestID'),
                   ),
                   backgroundColor:
-- 
2.39.5 (Apple Git-154)



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


             reply	other threads:[~2025-05-15 12:19 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-05-15 12:19 Shan Shaji [this message]
2025-07-18 14:56 ` Shan Shaji

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250515121924.59961-1-s.shaji@proxmox.com \
    --to=s.shaji@proxmox.com \
    --cc=pve-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal