redesign business menu

This commit is contained in:
Hesabix 2025-09-25 03:55:16 +03:30
parent 4bfd445635
commit 2dde8eeef9
9 changed files with 1253 additions and 43 deletions

View file

@ -745,6 +745,38 @@
"marketplace": "Marketplace", "marketplace": "Marketplace",
"viewMarketplace": "View Marketplace", "viewMarketplace": "View Marketplace",
"buyPlugins": "Buy Plugins", "buyPlugins": "Buy Plugins",
"viewInvoices": "View Invoices" "viewInvoices": "View Invoices",
"generalSettings": "General Settings",
"appearanceSettings": "Appearance Settings",
"advancedSettings": "Advanced Settings",
"businessSettingsDescription": "Manage business information and main settings",
"usersAndPermissionsDescription": "Manage users and set access levels",
"printDocuments": "Print Documents",
"printDocumentsDescription": "Configure print templates and formatting",
"languageDescription": "Select user interface language",
"themeDescription": "Choose light, dark or system theme",
"calendarDescription": "Select calendar type (Jalali or Gregorian)",
"dataBackup": "Data Backup",
"dataBackupDescription": "Create backup of all business data",
"dataRestore": "Data Restore",
"dataRestoreDescription": "Restore data from previous backup",
"systemLogs": "System Logs",
"systemLogsDescription": "View system reports and user activity logs",
"close": "Close",
"edit": "Edit",
"manage": "Manage",
"configure": "Configure",
"set": "Set",
"execute": "Execute",
"backup": "Backup",
"restore": "Restore",
"view": "View",
"businessSettingsDialogContent": "In this section you can manage business information, address, contact numbers and other details.",
"usersAndPermissionsDialogContent": "In this section you can add new users, set permissions and manage roles.",
"printDocumentsDialogContent": "In this section you can configure print templates, letterheads and printer settings.",
"dataBackupDialogContent": "In this section you can create a backup of all business data.",
"dataRestoreDialogContent": "In this section you can restore data from a previous backup.",
"systemLogsDialogContent": "In this section you can view system reports, errors and user activities.",
"accountManagement": "Account Management"
} }

View file

@ -744,6 +744,38 @@
"marketplace": "بازار افزونه‌ها", "marketplace": "بازار افزونه‌ها",
"viewMarketplace": "مشاهده افزونه‌ها", "viewMarketplace": "مشاهده افزونه‌ها",
"buyPlugins": "خرید افزونه‌ها", "buyPlugins": "خرید افزونه‌ها",
"viewInvoices": "صورت حساب‌ها" "viewInvoices": "صورت حساب‌ها",
"generalSettings": "تنظیمات عمومی",
"appearanceSettings": "تنظیمات ظاهری",
"advancedSettings": "تنظیمات پیشرفته",
"businessSettingsDescription": "مدیریت اطلاعات کسب و کار و تنظیمات اصلی",
"usersAndPermissionsDescription": "مدیریت کاربران و تعیین سطح دسترسی",
"printDocuments": "چاپ اسناد",
"printDocumentsDescription": "تنظیمات چاپ و قالب‌بندی اسناد",
"languageDescription": "انتخاب زبان رابط کاربری",
"themeDescription": "انتخاب تم روشن، تاریک یا سیستمی",
"calendarDescription": "انتخاب نوع تقویم (جلالی یا میلادی)",
"dataBackup": "پشتیبان‌گیری",
"dataBackupDescription": "ایجاد نسخه پشتیبان از اطلاعات",
"dataRestore": "بازیابی اطلاعات",
"dataRestoreDescription": "بازیابی اطلاعات از نسخه پشتیبان",
"systemLogs": "گزارش‌های سیستم",
"systemLogsDescription": "مشاهده گزارش‌ها و لاگ‌های سیستم",
"close": "بستن",
"edit": "ویرایش",
"manage": "مدیریت",
"configure": "پیکربندی",
"set": "تنظیم",
"execute": "اجرا",
"backup": "پشتیبان‌گیری",
"restore": "بازیابی",
"view": "مشاهده",
"businessSettingsDialogContent": "در این بخش می‌توانید اطلاعات کسب و کار، آدرس، شماره تماس و سایر جزئیات را مدیریت کنید.",
"usersAndPermissionsDialogContent": "در این بخش می‌توانید کاربران جدید اضافه کنید، دسترسی‌ها را تعیین کنید و نقش‌ها را مدیریت کنید.",
"printDocumentsDialogContent": "در این بخش می‌توانید قالب‌های چاپ، سربرگ‌ها و تنظیمات چاپگر را پیکربندی کنید.",
"dataBackupDialogContent": "در این بخش می‌توانید از تمام اطلاعات کسب و کار نسخه پشتیبان تهیه کنید.",
"dataRestoreDialogContent": "در این بخش می‌توانید اطلاعات را از نسخه پشتیبان قبلی بازیابی کنید.",
"systemLogsDialogContent": "در این بخش می‌توانید گزارش‌های سیستم، خطاها و فعالیت‌های کاربران را مشاهده کنید.",
"accountManagement": "مدیریت حساب کاربری"
} }

View file

@ -2561,7 +2561,7 @@ abstract class AppLocalizations {
/// No description provided for @systemLogsDescription. /// No description provided for @systemLogsDescription.
/// ///
/// In en, this message translates to: /// In en, this message translates to:
/// **'View system logs and monitoring'** /// **'View system reports and user activity logs'**
String get systemLogsDescription; String get systemLogsDescription;
/// No description provided for @backToSettings. /// No description provided for @backToSettings.
@ -4069,6 +4069,156 @@ abstract class AppLocalizations {
/// In en, this message translates to: /// In en, this message translates to:
/// **'Buy Plugins'** /// **'Buy Plugins'**
String get buyPlugins; String get buyPlugins;
/// No description provided for @appearanceSettings.
///
/// In en, this message translates to:
/// **'Appearance Settings'**
String get appearanceSettings;
/// No description provided for @advancedSettings.
///
/// In en, this message translates to:
/// **'Advanced Settings'**
String get advancedSettings;
/// No description provided for @businessSettingsDescription.
///
/// In en, this message translates to:
/// **'Manage business information and main settings'**
String get businessSettingsDescription;
/// No description provided for @usersAndPermissionsDescription.
///
/// In en, this message translates to:
/// **'Manage users and set access levels'**
String get usersAndPermissionsDescription;
/// No description provided for @printDocumentsDescription.
///
/// In en, this message translates to:
/// **'Configure print templates and formatting'**
String get printDocumentsDescription;
/// No description provided for @languageDescription.
///
/// In en, this message translates to:
/// **'Select user interface language'**
String get languageDescription;
/// No description provided for @themeDescription.
///
/// In en, this message translates to:
/// **'Choose light, dark or system theme'**
String get themeDescription;
/// No description provided for @calendarDescription.
///
/// In en, this message translates to:
/// **'Select calendar type (Jalali or Gregorian)'**
String get calendarDescription;
/// No description provided for @dataBackup.
///
/// In en, this message translates to:
/// **'Data Backup'**
String get dataBackup;
/// No description provided for @dataBackupDescription.
///
/// In en, this message translates to:
/// **'Create backup of all business data'**
String get dataBackupDescription;
/// No description provided for @dataRestore.
///
/// In en, this message translates to:
/// **'Data Restore'**
String get dataRestore;
/// No description provided for @dataRestoreDescription.
///
/// In en, this message translates to:
/// **'Restore data from previous backup'**
String get dataRestoreDescription;
/// No description provided for @manage.
///
/// In en, this message translates to:
/// **'Manage'**
String get manage;
/// No description provided for @configure.
///
/// In en, this message translates to:
/// **'Configure'**
String get configure;
/// No description provided for @set.
///
/// In en, this message translates to:
/// **'Set'**
String get set;
/// No description provided for @execute.
///
/// In en, this message translates to:
/// **'Execute'**
String get execute;
/// No description provided for @backup.
///
/// In en, this message translates to:
/// **'Backup'**
String get backup;
/// No description provided for @restore.
///
/// In en, this message translates to:
/// **'Restore'**
String get restore;
/// No description provided for @businessSettingsDialogContent.
///
/// In en, this message translates to:
/// **'In this section you can manage business information, address, contact numbers and other details.'**
String get businessSettingsDialogContent;
/// No description provided for @usersAndPermissionsDialogContent.
///
/// In en, this message translates to:
/// **'In this section you can add new users, set permissions and manage roles.'**
String get usersAndPermissionsDialogContent;
/// No description provided for @printDocumentsDialogContent.
///
/// In en, this message translates to:
/// **'In this section you can configure print templates, letterheads and printer settings.'**
String get printDocumentsDialogContent;
/// No description provided for @dataBackupDialogContent.
///
/// In en, this message translates to:
/// **'In this section you can create a backup of all business data.'**
String get dataBackupDialogContent;
/// No description provided for @dataRestoreDialogContent.
///
/// In en, this message translates to:
/// **'In this section you can restore data from a previous backup.'**
String get dataRestoreDialogContent;
/// No description provided for @systemLogsDialogContent.
///
/// In en, this message translates to:
/// **'In this section you can view system reports, errors and user activities.'**
String get systemLogsDialogContent;
/// No description provided for @accountManagement.
///
/// In en, this message translates to:
/// **'Account Management'**
String get accountManagement;
} }
class _AppLocalizationsDelegate class _AppLocalizationsDelegate

View file

@ -1280,7 +1280,8 @@ class AppLocalizationsEn extends AppLocalizations {
String get systemLogs => 'System Logs'; String get systemLogs => 'System Logs';
@override @override
String get systemLogsDescription => 'View system logs and monitoring'; String get systemLogsDescription =>
'View system reports and user activity logs';
@override @override
String get backToSettings => 'Back to Settings'; String get backToSettings => 'Back to Settings';
@ -2040,4 +2041,89 @@ class AppLocalizationsEn extends AppLocalizations {
@override @override
String get buyPlugins => 'Buy Plugins'; String get buyPlugins => 'Buy Plugins';
@override
String get appearanceSettings => 'Appearance Settings';
@override
String get advancedSettings => 'Advanced Settings';
@override
String get businessSettingsDescription =>
'Manage business information and main settings';
@override
String get usersAndPermissionsDescription =>
'Manage users and set access levels';
@override
String get printDocumentsDescription =>
'Configure print templates and formatting';
@override
String get languageDescription => 'Select user interface language';
@override
String get themeDescription => 'Choose light, dark or system theme';
@override
String get calendarDescription =>
'Select calendar type (Jalali or Gregorian)';
@override
String get dataBackup => 'Data Backup';
@override
String get dataBackupDescription => 'Create backup of all business data';
@override
String get dataRestore => 'Data Restore';
@override
String get dataRestoreDescription => 'Restore data from previous backup';
@override
String get manage => 'Manage';
@override
String get configure => 'Configure';
@override
String get set => 'Set';
@override
String get execute => 'Execute';
@override
String get backup => 'Backup';
@override
String get restore => 'Restore';
@override
String get businessSettingsDialogContent =>
'In this section you can manage business information, address, contact numbers and other details.';
@override
String get usersAndPermissionsDialogContent =>
'In this section you can add new users, set permissions and manage roles.';
@override
String get printDocumentsDialogContent =>
'In this section you can configure print templates, letterheads and printer settings.';
@override
String get dataBackupDialogContent =>
'In this section you can create a backup of all business data.';
@override
String get dataRestoreDialogContent =>
'In this section you can restore data from a previous backup.';
@override
String get systemLogsDialogContent =>
'In this section you can view system reports, errors and user activities.';
@override
String get accountManagement => 'Account Management';
} }

View file

@ -1267,10 +1267,10 @@ class AppLocalizationsFa extends AppLocalizations {
String get userManagementDescription => 'مدیریت کاربران، نقش‌ها و مجوزها'; String get userManagementDescription => 'مدیریت کاربران، نقش‌ها و مجوزها';
@override @override
String get systemLogs => 'لاگ‌های سیستم'; String get systemLogs => 'گزارش‌های سیستم';
@override @override
String get systemLogsDescription => 'مشاهده لاگ‌های سیستم و نظارت'; String get systemLogsDescription => 'مشاهده گزارش‌ها و لاگ‌های سیستم';
@override @override
String get backToSettings => 'بازگشت به تنظیمات'; String get backToSettings => 'بازگشت به تنظیمات';
@ -2029,4 +2029,87 @@ class AppLocalizationsFa extends AppLocalizations {
@override @override
String get buyPlugins => 'خرید افزونه‌ها'; String get buyPlugins => 'خرید افزونه‌ها';
@override
String get appearanceSettings => 'تنظیمات ظاهری';
@override
String get advancedSettings => 'تنظیمات پیشرفته';
@override
String get businessSettingsDescription =>
'مدیریت اطلاعات کسب و کار و تنظیمات اصلی';
@override
String get usersAndPermissionsDescription =>
'مدیریت کاربران و تعیین سطح دسترسی';
@override
String get printDocumentsDescription => 'تنظیمات چاپ و قالب‌بندی اسناد';
@override
String get languageDescription => 'انتخاب زبان رابط کاربری';
@override
String get themeDescription => 'انتخاب تم روشن، تاریک یا سیستمی';
@override
String get calendarDescription => 'انتخاب نوع تقویم (جلالی یا میلادی)';
@override
String get dataBackup => 'پشتیبان‌گیری';
@override
String get dataBackupDescription => 'ایجاد نسخه پشتیبان از اطلاعات';
@override
String get dataRestore => 'بازیابی اطلاعات';
@override
String get dataRestoreDescription => 'بازیابی اطلاعات از نسخه پشتیبان';
@override
String get manage => 'مدیریت';
@override
String get configure => 'پیکربندی';
@override
String get set => 'تنظیم';
@override
String get execute => 'اجرا';
@override
String get backup => 'پشتیبان‌گیری';
@override
String get restore => 'بازیابی';
@override
String get businessSettingsDialogContent =>
'در این بخش می‌توانید اطلاعات کسب و کار، آدرس، شماره تماس و سایر جزئیات را مدیریت کنید.';
@override
String get usersAndPermissionsDialogContent =>
'در این بخش می‌توانید کاربران جدید اضافه کنید، دسترسی‌ها را تعیین کنید و نقش‌ها را مدیریت کنید.';
@override
String get printDocumentsDialogContent =>
'در این بخش می‌توانید قالب‌های چاپ، سربرگ‌ها و تنظیمات چاپگر را پیکربندی کنید.';
@override
String get dataBackupDialogContent =>
'در این بخش می‌توانید از تمام اطلاعات کسب و کار نسخه پشتیبان تهیه کنید.';
@override
String get dataRestoreDialogContent =>
'در این بخش می‌توانید اطلاعات را از نسخه پشتیبان قبلی بازیابی کنید.';
@override
String get systemLogsDialogContent =>
'در این بخش می‌توانید گزارش‌های سیستم، خطاها و فعالیت‌های کاربران را مشاهده کنید.';
@override
String get accountManagement => 'مدیریت حساب کاربری';
} }

View file

@ -22,6 +22,7 @@ import 'pages/admin/email_settings_page.dart';
import 'pages/business/business_shell.dart'; import 'pages/business/business_shell.dart';
import 'pages/business/dashboard/business_dashboard_page.dart'; import 'pages/business/dashboard/business_dashboard_page.dart';
import 'pages/business/users_permissions_page.dart'; import 'pages/business/users_permissions_page.dart';
import 'pages/business/settings_page.dart';
import 'core/locale_controller.dart'; import 'core/locale_controller.dart';
import 'core/calendar_controller.dart'; import 'core/calendar_controller.dart';
import 'core/api_client.dart'; import 'core/api_client.dart';
@ -495,6 +496,26 @@ class _MyAppState extends State<MyApp> {
); );
}, },
), ),
GoRoute(
path: 'settings',
name: 'business_settings',
builder: (context, state) {
final businessId = int.parse(state.pathParameters['business_id']!);
return BusinessShell(
businessId: businessId,
authStore: _authStore!,
localeController: controller,
calendarController: _calendarController!,
themeController: themeController,
child: SettingsPage(
businessId: businessId,
localeController: controller,
calendarController: _calendarController!,
themeController: themeController,
),
);
},
),
// TODO: Add other business routes (sales, accounting, etc.) // TODO: Add other business routes (sales, accounting, etc.)
], ],
), ),

View file

@ -4,8 +4,7 @@ import '../../core/auth_store.dart';
import '../../core/locale_controller.dart'; import '../../core/locale_controller.dart';
import '../../core/calendar_controller.dart'; import '../../core/calendar_controller.dart';
import '../../theme/theme_controller.dart'; import '../../theme/theme_controller.dart';
import '../../widgets/settings_menu_button.dart'; import '../../widgets/combined_user_menu_button.dart';
import '../../widgets/user_account_menu_button.dart';
import 'package:hesabix_ui/l10n/app_localizations.dart'; import 'package:hesabix_ui/l10n/app_localizations.dart';
class BusinessShell extends StatefulWidget { class BusinessShell extends StatefulWidget {
@ -32,7 +31,6 @@ class BusinessShell extends StatefulWidget {
class _BusinessShellState extends State<BusinessShell> { class _BusinessShellState extends State<BusinessShell> {
int _hoverIndex = -1; int _hoverIndex = -1;
bool _isBasicToolsExpanded = false;
bool _isPeopleExpanded = false; bool _isPeopleExpanded = false;
bool _isProductsAndServicesExpanded = false; bool _isProductsAndServicesExpanded = false;
bool _isBankingExpanded = false; bool _isBankingExpanded = false;
@ -362,32 +360,9 @@ class _BusinessShellState extends State<BusinessShell> {
label: t.settings, label: t.settings,
icon: Icons.settings, icon: Icons.settings,
selectedIcon: Icons.settings, selectedIcon: Icons.settings,
path: null, // برای منوی بازشونده path: '/business/${widget.businessId}/settings',
type: _MenuItemType.expandable,
children: [
_MenuItem(
label: t.businessSettings,
icon: Icons.business,
selectedIcon: Icons.business,
path: '/business/${widget.businessId}/business-settings',
type: _MenuItemType.simple, type: _MenuItemType.simple,
), ),
_MenuItem(
label: t.printDocuments,
icon: Icons.print,
selectedIcon: Icons.print,
path: '/business/${widget.businessId}/print-documents',
type: _MenuItemType.simple,
),
_MenuItem(
label: t.usersAndPermissions,
icon: Icons.people_outline,
selectedIcon: Icons.people,
path: '/business/${widget.businessId}/users-permissions',
type: _MenuItemType.simple,
),
],
),
_MenuItem( _MenuItem(
label: t.pluginMarketplace, label: t.pluginMarketplace,
icon: Icons.store, icon: Icons.store,
@ -417,7 +392,6 @@ class _BusinessShellState extends State<BusinessShell> {
if (i == 4) _isBankingExpanded = true; // بانکداری در ایندکس 4 if (i == 4) _isBankingExpanded = true; // بانکداری در ایندکس 4
if (i == 6) _isAccountingMenuExpanded = true; // حسابداری در ایندکس 6 if (i == 6) _isAccountingMenuExpanded = true; // حسابداری در ایندکس 6
if (i == 8) _isWarehouseManagementExpanded = true; // انبارداری در ایندکس 8 if (i == 8) _isWarehouseManagementExpanded = true; // انبارداری در ایندکس 8
if (i == 9) _isBasicToolsExpanded = true; // تنظیمات در ایندکس 9
break; break;
} }
} }
@ -444,7 +418,6 @@ class _BusinessShellState extends State<BusinessShell> {
if (item.label == t.banking) _isBankingExpanded = !_isBankingExpanded; if (item.label == t.banking) _isBankingExpanded = !_isBankingExpanded;
if (item.label == t.accountingMenu) _isAccountingMenuExpanded = !_isAccountingMenuExpanded; if (item.label == t.accountingMenu) _isAccountingMenuExpanded = !_isAccountingMenuExpanded;
if (item.label == t.warehouseManagement) _isWarehouseManagementExpanded = !_isWarehouseManagementExpanded; if (item.label == t.warehouseManagement) _isWarehouseManagementExpanded = !_isWarehouseManagementExpanded;
if (item.label == t.settings) _isBasicToolsExpanded = !_isBasicToolsExpanded;
setState(() {}); setState(() {});
} }
} }
@ -482,7 +455,6 @@ class _BusinessShellState extends State<BusinessShell> {
if (item.label == t.banking) return _isBankingExpanded; if (item.label == t.banking) return _isBankingExpanded;
if (item.label == t.accountingMenu) return _isAccountingMenuExpanded; if (item.label == t.accountingMenu) return _isAccountingMenuExpanded;
if (item.label == t.warehouseManagement) return _isWarehouseManagementExpanded; if (item.label == t.warehouseManagement) return _isWarehouseManagementExpanded;
if (item.label == t.settings) return _isBasicToolsExpanded;
return false; return false;
} }
@ -533,14 +505,13 @@ class _BusinessShellState extends State<BusinessShell> {
), ),
), ),
actions: [ actions: [
SettingsMenuButton( CombinedUserMenuButton(
authStore: widget.authStore,
localeController: widget.localeController, localeController: widget.localeController,
calendarController: widget.calendarController, calendarController: widget.calendarController,
themeController: widget.themeController, themeController: widget.themeController,
), ),
const SizedBox(width: 8), const SizedBox(width: 4),
UserAccountMenuButton(authStore: widget.authStore),
const SizedBox(width: 8),
], ],
); );
@ -767,7 +738,6 @@ class _BusinessShellState extends State<BusinessShell> {
if (item.label == t.banking) _isBankingExpanded = !_isBankingExpanded; if (item.label == t.banking) _isBankingExpanded = !_isBankingExpanded;
if (item.label == t.accountingMenu) _isAccountingMenuExpanded = !_isAccountingMenuExpanded; if (item.label == t.accountingMenu) _isAccountingMenuExpanded = !_isAccountingMenuExpanded;
if (item.label == t.warehouseManagement) _isWarehouseManagementExpanded = !_isWarehouseManagementExpanded; if (item.label == t.warehouseManagement) _isWarehouseManagementExpanded = !_isWarehouseManagementExpanded;
if (item.label == t.settings) _isBasicToolsExpanded = !_isBasicToolsExpanded;
}); });
} else { } else {
onSelect(menuIndex); onSelect(menuIndex);
@ -927,7 +897,6 @@ class _BusinessShellState extends State<BusinessShell> {
if (item.label == t.banking) _isBankingExpanded = expanded; if (item.label == t.banking) _isBankingExpanded = expanded;
if (item.label == t.accountingMenu) _isAccountingMenuExpanded = expanded; if (item.label == t.accountingMenu) _isAccountingMenuExpanded = expanded;
if (item.label == t.warehouseManagement) _isWarehouseManagementExpanded = expanded; if (item.label == t.warehouseManagement) _isWarehouseManagementExpanded = expanded;
if (item.label == t.settings) _isBasicToolsExpanded = expanded;
}); });
}, },
children: item.children?.map((child) => ListTile( children: item.children?.map((child) => ListTile(

View file

@ -0,0 +1,368 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:hesabix_ui/l10n/app_localizations.dart';
import '../../core/locale_controller.dart';
import '../../core/calendar_controller.dart';
import '../../theme/theme_controller.dart';
import '../../widgets/calendar_switcher.dart';
import '../../widgets/language_switcher.dart';
import '../../widgets/theme_mode_switcher.dart';
class SettingsPage extends StatefulWidget {
final int businessId;
final LocaleController? localeController;
final CalendarController? calendarController;
final ThemeController? themeController;
const SettingsPage({
super.key,
required this.businessId,
this.localeController,
this.calendarController,
this.themeController,
});
@override
State<SettingsPage> createState() => _SettingsPageState();
}
class _SettingsPageState extends State<SettingsPage> {
@override
Widget build(BuildContext context) {
final t = AppLocalizations.of(context);
final cs = Theme.of(context).colorScheme;
return Scaffold(
appBar: AppBar(
title: Text(t.settings),
backgroundColor: cs.surface,
foregroundColor: cs.onSurface,
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// بخش تنظیمات عمومی
_buildSection(
context,
title: t.generalSettings,
icon: Icons.settings,
children: [
_buildSettingItem(
context,
title: t.businessSettings,
subtitle: t.businessSettingsDescription,
icon: Icons.business,
onTap: () => _showBusinessSettingsDialog(context),
),
_buildSettingItem(
context,
title: t.usersAndPermissions,
subtitle: t.usersAndPermissionsDescription,
icon: Icons.people_outline,
onTap: () => _showUsersPermissionsDialog(context),
),
_buildSettingItem(
context,
title: t.printDocuments,
subtitle: t.printDocumentsDescription,
icon: Icons.print,
onTap: () => _showPrintDocumentsDialog(context),
),
],
),
const SizedBox(height: 24),
// بخش تنظیمات ظاهری
_buildSection(
context,
title: t.appearanceSettings,
icon: Icons.palette,
children: [
_buildSettingItem(
context,
title: t.language,
subtitle: t.languageDescription,
icon: Icons.language,
trailing: widget.localeController != null
? LanguageSwitcher(controller: widget.localeController!)
: null,
),
_buildSettingItem(
context,
title: t.theme,
subtitle: t.themeDescription,
icon: Icons.brightness_6,
trailing: widget.themeController != null
? ThemeModeSwitcher(controller: widget.themeController!)
: null,
),
_buildSettingItem(
context,
title: t.calendar,
subtitle: t.calendarDescription,
icon: Icons.calendar_today,
trailing: widget.calendarController != null
? CalendarSwitcher(controller: widget.calendarController!)
: null,
),
],
),
const SizedBox(height: 24),
// بخش تنظیمات پیشرفته
_buildSection(
context,
title: t.advancedSettings,
icon: Icons.engineering,
children: [
_buildSettingItem(
context,
title: t.dataBackup,
subtitle: t.dataBackupDescription,
icon: Icons.backup,
onTap: () => _showDataBackupDialog(context),
),
_buildSettingItem(
context,
title: t.dataRestore,
subtitle: t.dataRestoreDescription,
icon: Icons.restore,
onTap: () => _showDataRestoreDialog(context),
),
_buildSettingItem(
context,
title: t.systemLogs,
subtitle: t.systemLogsDescription,
icon: Icons.assignment,
onTap: () => _showSystemLogsDialog(context),
),
],
),
],
),
),
);
}
Widget _buildSection(
BuildContext context, {
required String title,
required IconData icon,
required List<Widget> children,
}) {
final cs = Theme.of(context).colorScheme;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(icon, color: cs.primary, size: 24),
const SizedBox(width: 12),
Text(
title,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
color: cs.onSurface,
),
),
],
),
const SizedBox(height: 16),
...children,
],
);
}
Widget _buildSettingItem(
BuildContext context, {
required String title,
required String subtitle,
required IconData icon,
Widget? trailing,
VoidCallback? onTap,
}) {
final cs = Theme.of(context).colorScheme;
return Card(
margin: const EdgeInsets.only(bottom: 8),
child: ListTile(
leading: Icon(icon, color: cs.primary),
title: Text(
title,
style: TextStyle(
fontWeight: FontWeight.w500,
color: cs.onSurface,
),
),
subtitle: Text(
subtitle,
style: TextStyle(
color: cs.onSurfaceVariant,
fontSize: 12,
),
),
trailing: trailing ?? const Icon(Icons.arrow_forward_ios, size: 16),
onTap: onTap,
),
);
}
// دیالوگهای تنظیمات
void _showBusinessSettingsDialog(BuildContext context) {
final t = AppLocalizations.of(context);
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text(t.businessSettings),
content: Text(t.businessSettingsDialogContent),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text(t.close),
),
FilledButton(
onPressed: () {
Navigator.pop(context);
// Navigate to business dashboard for now (until business settings page is created)
context.go('/business/${widget.businessId}/dashboard');
},
child: Text(t.edit),
),
],
),
);
}
void _showUsersPermissionsDialog(BuildContext context) {
final t = AppLocalizations.of(context);
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text(t.usersAndPermissions),
content: Text(t.usersAndPermissionsDialogContent),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text(t.close),
),
FilledButton(
onPressed: () {
Navigator.pop(context);
// Navigate to users permissions page
context.go('/business/${widget.businessId}/users-permissions');
},
child: Text(t.manage),
),
],
),
);
}
void _showPrintDocumentsDialog(BuildContext context) {
final t = AppLocalizations.of(context);
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text(t.printDocuments),
content: Text(t.printDocumentsDialogContent),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text(t.close),
),
FilledButton(
onPressed: () {
Navigator.pop(context);
// Navigate to business dashboard for now (until print documents page is created)
context.go('/business/${widget.businessId}/dashboard');
},
child: Text(t.configure),
),
],
),
);
}
void _showDataBackupDialog(BuildContext context) {
final t = AppLocalizations.of(context);
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text(t.dataBackup),
content: Text(t.dataBackupDialogContent),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text(t.close),
),
FilledButton(
onPressed: () {
Navigator.pop(context);
// Navigate to business dashboard for now (until backup functionality is implemented)
context.go('/business/${widget.businessId}/dashboard');
},
child: Text(t.backup),
),
],
),
);
}
void _showDataRestoreDialog(BuildContext context) {
final t = AppLocalizations.of(context);
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text(t.dataRestore),
content: Text(t.dataRestoreDialogContent),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text(t.close),
),
FilledButton(
onPressed: () {
Navigator.pop(context);
// Navigate to business dashboard for now (until restore functionality is implemented)
context.go('/business/${widget.businessId}/dashboard');
},
child: Text(t.restore),
),
],
),
);
}
void _showSystemLogsDialog(BuildContext context) {
final t = AppLocalizations.of(context);
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text(t.systemLogs),
content: Text(t.systemLogsDialogContent),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text(t.close),
),
FilledButton(
onPressed: () {
Navigator.pop(context);
// Navigate to business dashboard for now (until system logs page is created)
context.go('/business/${widget.businessId}/dashboard');
},
child: Text(t.view),
),
],
),
);
}
}

View file

@ -0,0 +1,469 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:hesabix_ui/l10n/app_localizations.dart';
import '../core/auth_store.dart';
import '../core/locale_controller.dart';
import '../core/calendar_controller.dart';
import '../theme/theme_controller.dart';
import 'calendar_switcher.dart';
import 'language_switcher.dart';
import 'theme_mode_switcher.dart';
class CombinedUserMenuButton extends StatelessWidget {
final AuthStore authStore;
final LocaleController? localeController;
final CalendarController? calendarController;
final ThemeController? themeController;
const CombinedUserMenuButton({
super.key,
required this.authStore,
this.localeController,
this.calendarController,
this.themeController,
});
void _showUserMenu(BuildContext context) {
final t = AppLocalizations.of(context);
final cs = Theme.of(context).colorScheme;
showDialog(
context: context,
barrierDismissible: true,
builder: (context) => Dialog(
backgroundColor: Colors.transparent,
elevation: 0,
child: Container(
constraints: const BoxConstraints(maxWidth: 320),
decoration: BoxDecoration(
color: cs.surface,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 20,
offset: const Offset(0, 8),
),
],
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// Header با آواتار و نام کاربر
Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: cs.primaryContainer.withOpacity(0.1),
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(16),
topRight: Radius.circular(16),
),
),
child: Row(
children: [
CircleAvatar(
radius: 24,
backgroundColor: cs.primary,
child: Icon(
Icons.person,
color: cs.onPrimary,
size: 28,
),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
t.profile,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
color: cs.onSurface,
),
),
Text(
'کاربر حسابیکس',
style: TextStyle(
fontSize: 14,
color: cs.onSurfaceVariant,
),
),
],
),
),
],
),
),
// محتوای دیالوگ
Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
// آیتم حساب کاربری
Container(
width: double.infinity,
decoration: BoxDecoration(
color: cs.primaryContainer.withOpacity(0.1),
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: cs.primary.withOpacity(0.2),
width: 1,
),
),
child: Material(
color: Colors.transparent,
child: InkWell(
borderRadius: BorderRadius.circular(12),
onTap: () {
context.pop();
context.go('/user/profile/dashboard');
},
child: Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
CircleAvatar(
radius: 20,
backgroundColor: cs.primary,
child: Icon(
Icons.account_circle,
color: cs.onPrimary,
size: 24,
),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
t.profile,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: cs.onSurface,
),
),
Text(
t.accountManagement,
style: TextStyle(
fontSize: 14,
color: cs.onSurfaceVariant,
),
),
],
),
),
Icon(
Icons.arrow_forward_ios,
color: cs.onSurfaceVariant,
size: 16,
),
],
),
),
),
),
),
const SizedBox(height: 16),
// بخش تنظیمات
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: cs.surfaceContainerHighest.withOpacity(0.3),
borderRadius: BorderRadius.circular(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(
Icons.settings,
color: cs.primary,
size: 20,
),
const SizedBox(width: 8),
Text(
t.settings,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: cs.onSurface,
),
),
],
),
const SizedBox(height: 16),
// تنظیمات تقویم
if (calendarController != null) ...[
_buildSettingRow(
context,
icon: Icons.calendar_today,
title: t.calendar,
child: CalendarSwitcher(controller: calendarController!),
),
const SizedBox(height: 12),
],
// تنظیمات زبان
if (localeController != null) ...[
_buildSettingRow(
context,
icon: Icons.language,
title: t.language,
child: LanguageSwitcher(controller: localeController!),
),
const SizedBox(height: 12),
],
// تنظیمات تم
if (themeController != null) ...[
_buildSettingRow(
context,
icon: Icons.palette,
title: t.theme,
child: ThemeModeSwitcher(controller: themeController!),
),
],
],
),
),
const SizedBox(height: 16),
// دکمه خروج
Container(
width: double.infinity,
decoration: BoxDecoration(
color: cs.errorContainer.withOpacity(0.1),
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: cs.error.withOpacity(0.2),
width: 1,
),
),
child: Material(
color: Colors.transparent,
child: InkWell(
borderRadius: BorderRadius.circular(12),
onTap: () {
context.pop();
_confirmLogout(context);
},
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 12,
),
child: Row(
children: [
Icon(
Icons.logout,
color: cs.error,
size: 20,
),
const SizedBox(width: 12),
Text(
t.logout,
style: TextStyle(
color: cs.error,
fontWeight: FontWeight.w500,
fontSize: 16,
),
),
],
),
),
),
),
),
],
),
),
],
),
),
),
);
}
Widget _buildSettingRow(
BuildContext context, {
required IconData icon,
required String title,
required Widget child,
}) {
final cs = Theme.of(context).colorScheme;
return Row(
children: [
Icon(
icon,
color: cs.onSurfaceVariant,
size: 20,
),
const SizedBox(width: 12),
Expanded(
child: Text(
title,
style: TextStyle(
color: cs.onSurface,
fontSize: 14,
fontWeight: FontWeight.w500,
),
),
),
child,
],
);
}
void _confirmLogout(BuildContext context) {
final t = AppLocalizations.of(context);
final cs = Theme.of(context).colorScheme;
showDialog(
context: context,
barrierDismissible: true,
builder: (context) => Dialog(
backgroundColor: Colors.transparent,
elevation: 0,
child: Container(
constraints: const BoxConstraints(maxWidth: 400),
decoration: BoxDecoration(
color: cs.surface,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 20,
offset: const Offset(0, 8),
),
],
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// Header
Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: cs.errorContainer.withOpacity(0.1),
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(16),
topRight: Radius.circular(16),
),
),
child: Row(
children: [
CircleAvatar(
radius: 20,
backgroundColor: cs.error,
child: Icon(
Icons.logout,
color: cs.onError,
size: 20,
),
),
const SizedBox(width: 12),
Expanded(
child: Text(
t.logoutConfirmTitle,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
color: cs.onSurface,
),
),
),
],
),
),
// Content
Padding(
padding: const EdgeInsets.all(20),
child: Text(
t.logoutConfirmMessage,
style: TextStyle(
fontSize: 16,
color: cs.onSurfaceVariant,
height: 1.5,
),
textAlign: TextAlign.center,
),
),
// Actions
Padding(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 20),
child: Row(
children: [
Expanded(
child: OutlinedButton(
onPressed: () => context.pop(),
style: OutlinedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
child: Text(t.cancel),
),
),
const SizedBox(width: 12),
Expanded(
child: FilledButton(
onPressed: () async {
context.pop();
await authStore.saveApiKey(null);
if (!context.mounted) return;
ScaffoldMessenger.of(context)
..hideCurrentSnackBar()
..showSnackBar(SnackBar(content: Text(t.logoutDone)));
context.go('/login');
},
style: FilledButton.styleFrom(
backgroundColor: cs.error,
foregroundColor: cs.onError,
padding: const EdgeInsets.symmetric(vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
child: Text(t.logout),
),
),
],
),
),
],
),
),
),
);
}
@override
Widget build(BuildContext context) {
final cs = Theme.of(context).colorScheme;
return IconButton(
icon: CircleAvatar(
radius: 16,
backgroundColor: cs.surfaceContainerHighest,
foregroundColor: cs.onSurface,
child: const Icon(Icons.person, size: 18),
),
onPressed: () => _showUserMenu(context),
tooltip: AppLocalizations.of(context).profile,
);
}
}