feat: add app version display to user profile bar and update version number in pubspec.yaml

This commit is contained in:
Vaibhav Surve 2025-11-20 17:19:48 +05:30
parent 846ca64402
commit efefb1c34b
2 changed files with 149 additions and 47 deletions

View File

@ -2,6 +2,7 @@ import 'dart:ui';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_lucide/flutter_lucide.dart'; import 'package:flutter_lucide/flutter_lucide.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:marco/helpers/services/storage/local_storage.dart'; import 'package:marco/helpers/services/storage/local_storage.dart';
import 'package:marco/helpers/utils/mixins/ui_mixin.dart'; import 'package:marco/helpers/utils/mixins/ui_mixin.dart';
import 'package:marco/helpers/widgets/my_spacing.dart'; import 'package:marco/helpers/widgets/my_spacing.dart';
@ -15,7 +16,6 @@ import 'package:marco/view/tenant/tenant_selection_screen.dart';
import 'package:marco/controller/tenant/tenant_switch_controller.dart'; import 'package:marco/controller/tenant/tenant_switch_controller.dart';
import 'package:marco/helpers/theme/theme_editor_widget.dart'; import 'package:marco/helpers/theme/theme_editor_widget.dart';
class UserProfileBar extends StatefulWidget { class UserProfileBar extends StatefulWidget {
final bool isCondensed; final bool isCondensed;
const UserProfileBar({Key? key, this.isCondensed = false}) : super(key: key); const UserProfileBar({Key? key, this.isCondensed = false}) : super(key: key);
@ -30,6 +30,7 @@ class _UserProfileBarState extends State<UserProfileBar>
bool _isLoading = true; bool _isLoading = true;
bool hasMpin = true; bool hasMpin = true;
bool _isThemeEditorVisible = false; bool _isThemeEditorVisible = false;
String _appVersion = '';
@override @override
void initState() { void initState() {
@ -40,6 +41,11 @@ class _UserProfileBarState extends State<UserProfileBar>
Future<void> _initData() async { Future<void> _initData() async {
employeeInfo = LocalStorage.getEmployeeInfo()!; employeeInfo = LocalStorage.getEmployeeInfo()!;
hasMpin = await LocalStorage.getIsMpin(); hasMpin = await LocalStorage.getIsMpin();
// Fetch app version
PackageInfo packageInfo = await PackageInfo.fromPlatform();
_appVersion = '${packageInfo.version}+${packageInfo.buildNumber}';
setState(() => _isLoading = false); setState(() => _isLoading = false);
} }
@ -79,55 +85,155 @@ class _UserProfileBarState extends State<UserProfileBar>
), ),
), ),
child: SafeArea( child: SafeArea(
bottom: true, bottom: true,
child: Stack( child: Stack(
children: [ children: [
Offstage( Offstage(
offstage: _isThemeEditorVisible, offstage: _isThemeEditorVisible,
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
_isLoading _isLoading
? const _LoadingSection() ? const _LoadingSection()
: _userProfileSection(isCondensed), : _userProfileSection(isCondensed),
if (!_isLoading && !isCondensed) _switchTenantRow(), if (!_isLoading && !isCondensed) _switchTenantRow(),
MySpacing.height(12), MySpacing.height(12),
Divider( Divider(
indent: 18, indent: 18,
endIndent: 18, endIndent: 18,
thickness: 0.7, thickness: 0.7,
color: Colors.grey.withOpacity(0.25), color: Colors.grey.withOpacity(0.25),
), ),
MySpacing.height(12), MySpacing.height(12),
_supportAndSettingsMenu(isCondensed), _supportAndSettingsMenu(isCondensed),
const Spacer(), MySpacing.height(12),
Divider(
indent: 18, // Subtle version text for expanded mode
endIndent: 18, if (!isCondensed && _appVersion.isNotEmpty)
thickness: 0.35, _versionText(),
color: Colors.grey.withOpacity(0.18),
), const Spacer(),
_logoutButton(isCondensed), Divider(
], indent: 18,
), endIndent: 18,
thickness: 0.35,
color: Colors.grey.withOpacity(0.18),
),
_logoutButton(isCondensed),
],
), ),
Offstage( ),
offstage: !_isThemeEditorVisible, Offstage(
child: ThemeEditorWidget( offstage: !_isThemeEditorVisible,
onClose: () { child: ThemeEditorWidget(
setState(() => _isThemeEditorVisible = false); onClose: () {
}, setState(() => _isThemeEditorVisible = false);
), },
), ),
], ),
)),
// Floating badge for condensed mode
if (isCondensed && _appVersion.isNotEmpty) _versionBadge(),
],
),
),
), ),
), ),
), ),
); );
} }
// ==================== CONTINUE EXISTING CODE ===================== // =================== Version Widgets ===================
Widget _versionText() {
return Padding(
padding: const EdgeInsets.only(top: 4, bottom: 12),
child: Center(
child: ClipRRect(
borderRadius: BorderRadius.circular(16),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 6),
decoration: BoxDecoration(
color: Colors.grey.shade100.withOpacity(0.85),
borderRadius: BorderRadius.circular(16),
border: Border.all(
color: Colors.grey.shade200,
width: 0.7,
),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.12),
blurRadius: 3,
offset: const Offset(0, 1),
),
],
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.info_outline, size: 14, color: Colors.grey[700]),
const SizedBox(width: 4),
Text(
'Version: $_appVersion',
style: TextStyle(
fontSize: 12,
color: Colors.grey[800],
fontWeight: FontWeight.w600,
),
),
],
),
),
),
),
),
);
}
Widget _versionBadge() {
return Positioned(
bottom: 10,
right: 14,
child: ClipRRect(
borderRadius: BorderRadius.circular(16),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 5),
decoration: BoxDecoration(
color: Colors.grey.shade100.withOpacity(0.85),
borderRadius: BorderRadius.circular(16),
border: Border.all(
color: Colors.grey.shade300,
width: 1,
),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.17),
blurRadius: 6,
offset: const Offset(0, 2),
),
],
),
child: Text(
_appVersion,
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Colors.black87,
letterSpacing: 0.4,
),
),
),
),
),
);
}
// =================== Existing methods ===================
Widget _switchTenantRow() { Widget _switchTenantRow() {
final TenantSwitchController tenantSwitchController = final TenantSwitchController tenantSwitchController =
Get.put(TenantSwitchController()); Get.put(TenantSwitchController());
@ -443,24 +549,20 @@ class _UserProfileBarState extends State<UserProfileBar>
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
// Top icon
Icon(LucideIcons.log_out, size: 56, color: primaryColor), Icon(LucideIcons.log_out, size: 56, color: primaryColor),
MySpacing.height(18), MySpacing.height(18),
// Title
MyText.titleLarge( MyText.titleLarge(
"Logout Confirmation", "Logout Confirmation",
fontWeight: 700, fontWeight: 700,
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
MySpacing.height(14), MySpacing.height(14),
// Subtitle
MyText.bodyMedium( MyText.bodyMedium(
"Are you sure you want to logout?\nYou will need to login again to continue.", "Are you sure you want to logout?\nYou will need to login again to continue.",
color: Colors.grey[700], color: Colors.grey[700],
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
MySpacing.height(30), MySpacing.height(30),
// Buttons
Row( Row(
children: [ children: [
Expanded( Expanded(

View File

@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts # In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix. # of the product and file versions while build-number is used as the build suffix.
version: 1.0.0+14 version: 1.0.0+15
environment: environment:
sdk: ^3.5.3 sdk: ^3.5.3