adding multilingual support

This commit is contained in:
Azmat-7860
2026-10-03 15:04:48 +05:30
parent 3785ea1e45
commit 0d7785b242
51 changed files with 3007 additions and 250 deletions
+9
View File
@@ -7,6 +7,15 @@
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
analyzer:
exclude:
- build/**
- android/**
- ios/**
- web/**
- windows/**
- macos/**
- linux/**
include: package:flutter_lints/flutter.yaml
linter:
@@ -0,0 +1,8 @@
{
"student": "Student",
"create_student": "Create Student",
"update_student": "Update Student",
"name": "Name",
"phone_number": "Phone Number",
"email": "Email"
}
@@ -0,0 +1,8 @@
{
"student": "छात्र",
"create_student": "छात्र बनाएँ",
"update_student": "छात्र अपडेट करें",
"name": "नाम",
"phone_number": "फ़ोन नंबर",
"email": "ईमेल"
}
+4
View File
@@ -0,0 +1,4 @@
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
output-dir: lib/l10n
@@ -1,6 +1,7 @@
import 'dart:typed_data';
import 'dart:io';
import 'package:flutter/material.dart';
import '../../../l10n/app_localizations.dart';
import 'package:file_picker/file_picker.dart';
import 'base_field.dart';
import '../utils/entity_field_store.dart';
@@ -63,7 +64,9 @@ class AudioUploadField extends BaseField {
}
},
icon: const Icon(Icons.audiotrack_rounded),
label: const Text('Add Audio'),
label: Builder(
builder: (ctx) =>
Text(AppLocalizations.of(ctx)!.addAudio)),
),
],
),
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import '../../../l10n/app_localizations.dart';
import 'base_field.dart';
import '../../../shared/widgets/inputs/modern_text_field.dart';
@@ -255,7 +256,7 @@ class _AutocompleteMultiSelectWidgetState
const SizedBox(width: 8),
Expanded(
child: Text(
'No results',
AppLocalizations.of(context)!.noResults,
style: TextStyle(
color:
widget.colorScheme.onSurfaceVariant),
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import '../../../l10n/app_localizations.dart';
import 'package:barcode_widget/barcode_widget.dart';
import 'base_field.dart';
@@ -73,19 +74,22 @@ class BarcodeField extends BaseField {
),
),
const SizedBox(width: 8),
IconButton(
tooltip: 'Scan Barcode',
icon: Icon(Icons.document_scanner_rounded,
color: colorScheme.primary),
onPressed: scanner == null
? null
: () async {
final val = await scanner!.call();
if (val != null) {
controller.text = val;
onChanged?.call();
}
},
Builder(
builder: (ctx) => IconButton(
tooltip:
AppLocalizations.of(ctx)!.scanBarcode,
icon: Icon(Icons.document_scanner_rounded,
color: colorScheme.primary),
onPressed: scanner == null
? null
: () async {
final val = await scanner!.call();
if (val != null) {
controller.text = val;
onChanged?.call();
}
},
),
),
],
),
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import '../../../l10n/app_localizations.dart';
import 'base_field.dart';
/// Read-only Data Grid field
@@ -96,7 +97,7 @@ class _DataGridFieldWidgetState extends State<_DataGridFieldWidget> {
}
final data = snapshot.data ?? const <Map<String, dynamic>>[];
if (data.isEmpty) {
return Text('No data available',
return Text(AppLocalizations.of(context)!.noDataAvailable,
style: TextStyle(color: colorScheme.onSurfaceVariant));
}
final columns = data.first.keys.toList();
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import '../../../l10n/app_localizations.dart';
import 'base_field.dart';
import '../../../shared/widgets/inputs/modern_text_field.dart';
@@ -152,7 +153,8 @@ class _DynamicDropdownWidgetState extends State<_DynamicDropdownWidget> {
children: [
TextField(
decoration: InputDecoration(
hintText: 'Search ${widget.label.toLowerCase()}',
hintText: AppLocalizations.of(context)!
.searchEntity(widget.label),
prefixIcon: const Icon(Icons.search),
border: const OutlineInputBorder(),
),
@@ -162,7 +164,8 @@ class _DynamicDropdownWidgetState extends State<_DynamicDropdownWidget> {
Flexible(
child: filtered.isEmpty
? Center(
child: Text('No results',
child: Text(
AppLocalizations.of(context)!.noResults,
style: TextStyle(color: cs.onSurfaceVariant)),
)
: ListView.separated(
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import '../../../l10n/app_localizations.dart';
import 'base_field.dart';
import '../../../shared/widgets/inputs/modern_text_field.dart';
@@ -146,7 +147,8 @@ class _DynamicMultiSelectWidgetState extends State<_DynamicMultiSelectWidget> {
children: [
TextField(
decoration: InputDecoration(
hintText: 'Search ${widget.label.toLowerCase()}',
hintText: AppLocalizations.of(context)!
.searchEntity(widget.label),
prefixIcon: const Icon(Icons.search),
border: const OutlineInputBorder(),
),
@@ -156,7 +158,8 @@ class _DynamicMultiSelectWidgetState extends State<_DynamicMultiSelectWidget> {
Flexible(
child: filtered.isEmpty
? Center(
child: Text('No results',
child: Text(
AppLocalizations.of(context)!.noResults,
style: TextStyle(color: cs.onSurfaceVariant)),
)
: ListView.separated(
@@ -188,7 +191,8 @@ class _DynamicMultiSelectWidgetState extends State<_DynamicMultiSelectWidget> {
widget.onChanged?.call();
Navigator.of(context).pop();
},
child: const Text('Clear'),
child: Text(
AppLocalizations.of(context)!.clearBtn),
),
const Spacer(),
ElevatedButton(
@@ -199,7 +203,8 @@ class _DynamicMultiSelectWidgetState extends State<_DynamicMultiSelectWidget> {
widget.onChanged?.call();
Navigator.of(context).pop();
},
child: const Text('Done'),
child: Text(
AppLocalizations.of(context)!.doneBtn),
),
],
),
@@ -1,6 +1,7 @@
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:file_picker/file_picker.dart';
import '../../../l10n/app_localizations.dart';
import 'base_field.dart';
import '../utils/entity_field_store.dart';
@@ -62,7 +63,9 @@ class FileUploadField extends BaseField {
}
},
icon: const Icon(Icons.attach_file_rounded),
label: const Text('Add Files'),
label: Builder(
builder: (ctx) =>
Text(AppLocalizations.of(ctx)!.addFiles)),
),
],
),
@@ -1,6 +1,7 @@
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import '../../../l10n/app_localizations.dart';
import 'base_field.dart';
import '../utils/entity_field_store.dart';
@@ -57,7 +58,9 @@ class ImageUploadField extends BaseField {
}
},
icon: const Icon(Icons.image_rounded),
label: const Text('Add Image'),
label: Builder(
builder: (ctx) =>
Text(AppLocalizations.of(ctx)!.addImage)),
),
],
),
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import '../../../l10n/app_localizations.dart';
import 'base_field.dart';
import '../ui/entity_form.dart';
import 'dart:convert';
@@ -553,7 +554,9 @@ class _OneToManyWidgetState extends State<_OneToManyWidget> {
child: ElevatedButton.icon(
onPressed: () => _addRow(),
icon: Icon(Icons.add, color: cs.onPrimary),
label: Text('Add ${widget.label}',
label: Text(
AppLocalizations.of(context)!
.addEntity(widget.label),
style: TextStyle(color: cs.onPrimary)),
style: ElevatedButton.styleFrom(
backgroundColor: cs.primary,
@@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../../l10n/app_localizations.dart';
import '../../../core/constants/ui_constants.dart';
import '../../../core/providers/dynamic_theme_provider.dart';
import '../ui/entity_form.dart';
@@ -147,7 +147,8 @@ class RelatedEntityInsertField extends BaseField {
setLocal(() => isSubmitting = false);
}
},
submitButtonText: 'Create',
submitButtonText: AppLocalizations.of(context)!
.createEntity(relationTitle),
isLoading: isSubmitting,
),
),
@@ -156,7 +157,8 @@ class RelatedEntityInsertField extends BaseField {
onPressed: isSubmitting
? null
: () => Navigator.of(dialogContext).pop(),
child: const Text('Cancel'),
child: Text(
AppLocalizations.of(dialogContext)!.cancel),
),
],
);
@@ -402,7 +404,8 @@ class _RelatedEntityInsertWidgetState
ElevatedButton.icon(
onPressed: _creating ? null : _openInsertDialog,
icon: Icon(Icons.add_rounded, color: cs.onPrimary, size: 18),
label: Text('Insert',
label: Text(
AppLocalizations.of(context)!.insertBtn,
style: TextStyle(
color: cs.onPrimary, fontWeight: FontWeight.w600)),
style: ElevatedButton.styleFrom(
@@ -491,7 +494,8 @@ class _RelatedEntityInsertWidgetState
TextButton(
onPressed:
isSubmitting ? null : () => Navigator.of(context).pop(),
child: const Text('Cancel'),
child: Text(
AppLocalizations.of(context)!.cancel),
),
],
);
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import '../../../l10n/app_localizations.dart';
import 'base_field.dart';
import '../ui/entity_form.dart';
@@ -143,7 +144,8 @@ class _ValueListPickerWidgetState extends State<_ValueListPickerWidget> {
strokeWidth: 2, color: cs.primary),
),
const SizedBox(width: 12),
Text('Loading...',
Text(
AppLocalizations.of(context)!.loading,
style: TextStyle(color: cs.onSurfaceVariant)),
],
),
@@ -152,7 +154,7 @@ class _ValueListPickerWidgetState extends State<_ValueListPickerWidget> {
if (snapshot.hasError || _loadError != null) {
final String msg = snapshot.error?.toString() ??
_loadError ??
'Failed to load';
AppLocalizations.of(context)!.errorLoadingData;
return Padding(
padding: const EdgeInsets.all(16),
child: Container(
@@ -186,13 +188,15 @@ class _ValueListPickerWidgetState extends State<_ValueListPickerWidget> {
Icon(Icons.inbox_rounded,
color: cs.onSurfaceVariant, size: 36),
const SizedBox(height: 8),
Text('No data found',
Text(
AppLocalizations.of(context)!.noDataFound,
style: TextStyle(color: cs.onSurfaceVariant)),
const SizedBox(height: 12),
ElevatedButton.icon(
onPressed: () => Navigator.of(context).pop(),
icon: const Icon(Icons.close_rounded),
label: const Text('Close'),
label: Text(
AppLocalizations.of(context)!.close),
style: ElevatedButton.styleFrom(
backgroundColor: cs.primary,
foregroundColor: cs.onPrimary,
@@ -2,6 +2,7 @@ import 'dart:typed_data';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:file_picker/file_picker.dart';
import '../../../l10n/app_localizations.dart';
import 'base_field.dart';
import '../utils/entity_field_store.dart';
@@ -63,7 +64,9 @@ class VideoUploadField extends BaseField {
}
},
icon: const Icon(Icons.video_library_rounded),
label: const Text('Add Video'),
label: Builder(
builder: (ctx) =>
Text(AppLocalizations.of(ctx)!.addVideo)),
),
],
),
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../../l10n/app_localizations.dart';
import '../../../core/providers/dynamic_theme_provider.dart';
import '../../../core/constants/ui_constants.dart';
import '../../../shared/widgets/app_bar/modern_app_bar.dart';
@@ -408,7 +409,7 @@ class _EntityDetailsState extends State<EntityDetails>
children: [
Expanded(
child: ModernButton(
text: 'Edit',
text: AppLocalizations.of(context)!.edit,
type: ModernButtonType.secondary,
size: ModernButtonSize.large,
onPressed: () => widget.onEdit(widget.entity),
@@ -418,7 +419,7 @@ class _EntityDetailsState extends State<EntityDetails>
const SizedBox(width: UIConstants.spacing16),
Expanded(
child: ModernButton(
text: 'Delete',
text: AppLocalizations.of(context)!.delete,
type: ModernButtonType.danger,
size: ModernButtonSize.large,
onPressed: () => _showDeleteDialog(colorScheme),
@@ -386,6 +386,7 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../../l10n/app_localizations.dart';
import '../../../core/providers/dynamic_theme_provider.dart';
import '../fields/base_field.dart';
import '../fields/dependent_dropdown_field.dart';
@@ -562,7 +563,9 @@ class _EntityFormState extends State<EntityForm> {
final pass = passwordByGroup[gid] ?? '';
if (confirm.isNotEmpty && confirm != pass) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Passwords do not match')),
SnackBar(
content: Text(AppLocalizations.of(context)!
.passwordsDoNotMatch)),
);
return;
}
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../../core/providers/dynamic_theme_provider.dart';
import '../../../core/constants/ui_constants.dart';
import '../../../l10n/app_localizations.dart';
import '../../../shared/widgets/app_bar/modern_app_bar.dart';
import 'entity_card.dart';
@@ -106,7 +107,7 @@ class _EntityListState extends State<EntityList> with TickerProviderStateMixin {
TextButton(
onPressed: widget.onInsertAction,
child: Text(
widget.insertActionLabel ?? 'Unknown',
widget.insertActionLabel ?? AppLocalizations.of(context)!.unknown,
style: TextStyle(
color: colorScheme.primary,
fontWeight: FontWeight.w600,
@@ -117,7 +118,7 @@ class _EntityListState extends State<EntityList> with TickerProviderStateMixin {
IconButton(
onPressed: widget.onAddNew,
icon: Icon(Icons.add_rounded, color: colorScheme.primary),
tooltip: 'Add New',
tooltip: AppLocalizations.of(context)!.addNew,
),
],
),
@@ -175,7 +176,8 @@ class _EntityListState extends State<EntityList> with TickerProviderStateMixin {
fontWeight: FontWeight.w500,
),
decoration: InputDecoration(
hintText: 'Search ${widget.title.toLowerCase()}...',
hintText: AppLocalizations.of(context)!
.searchEntity(widget.title.toLowerCase()),
hintStyle: TextStyle(
color: colorScheme.onSurface.withOpacity(0.6),
fontSize: 16,
@@ -214,7 +216,7 @@ class _EntityListState extends State<EntityList> with TickerProviderStateMixin {
color: colorScheme.onSurface.withOpacity(0.8),
size: 22,
),
tooltip: 'Refresh',
tooltip: AppLocalizations.of(context)!.refresh,
),
],
),
@@ -245,7 +247,7 @@ class _EntityListState extends State<EntityList> with TickerProviderStateMixin {
CircularProgressIndicator(color: colorScheme.primary, strokeWidth: 3),
const SizedBox(height: UIConstants.spacing16),
Text(
'Loading ${widget.title.toLowerCase()}...',
AppLocalizations.of(context)!.loadingEntity(widget.title.toLowerCase()),
style: TextStyle(
color: colorScheme.onSurface.withOpacity(0.7),
fontSize: 16,
@@ -277,7 +279,7 @@ class _EntityListState extends State<EntityList> with TickerProviderStateMixin {
),
const SizedBox(height: UIConstants.spacing16),
Text(
'Error Loading Data',
AppLocalizations.of(context)!.errorLoadingData,
style: TextStyle(
color: colorScheme.onSurface,
fontSize: 18,
@@ -286,7 +288,7 @@ class _EntityListState extends State<EntityList> with TickerProviderStateMixin {
),
const SizedBox(height: UIConstants.spacing8),
Text(
widget.errorMessage ?? 'Something went wrong',
widget.errorMessage ?? AppLocalizations.of(context)!.somethingWentWrong,
style: TextStyle(
color: colorScheme.onSurface.withOpacity(0.7),
fontSize: 14,
@@ -299,7 +301,7 @@ class _EntityListState extends State<EntityList> with TickerProviderStateMixin {
onPressed: widget.onRefresh,
icon: Icon(Icons.refresh_rounded, color: colorScheme.onPrimary),
label: Text(
'Retry',
AppLocalizations.of(context)!.retry,
style: TextStyle(
color: colorScheme.onPrimary,
fontWeight: FontWeight.w600,
@@ -344,7 +346,7 @@ class _EntityListState extends State<EntityList> with TickerProviderStateMixin {
),
const SizedBox(height: UIConstants.spacing16),
Text(
'No ${widget.title.toLowerCase()} found',
AppLocalizations.of(context)!.noEntityFound(widget.title.toLowerCase()),
style: TextStyle(
color: colorScheme.onSurface,
fontSize: 18,
@@ -354,8 +356,9 @@ class _EntityListState extends State<EntityList> with TickerProviderStateMixin {
const SizedBox(height: UIConstants.spacing8),
Text(
widget.searchQuery.isNotEmpty
? 'Try adjusting your search terms'
: 'Start by adding your first ${widget.title.toLowerCase()}',
? AppLocalizations.of(context)!.adjustSearchTerms
: AppLocalizations.of(context)!
.startByAdding(widget.title.toLowerCase()),
style: TextStyle(
color: colorScheme.onSurface.withOpacity(0.7),
fontSize: 14,
@@ -369,7 +372,7 @@ class _EntityListState extends State<EntityList> with TickerProviderStateMixin {
onPressed: widget.onAddNew,
icon: Icon(Icons.add_rounded, color: colorScheme.onPrimary),
label: Text(
'Add ${widget.title}',
AppLocalizations.of(context)!.addEntity(widget.title),
style: TextStyle(
color: colorScheme.onPrimary,
fontWeight: FontWeight.w600,
@@ -1,3 +1,4 @@
import 'package:base_project/l10n/app_localizations.dart';
import 'package:flutter/material.dart';
class ReusableDropdownField extends StatelessWidget {
@@ -46,9 +47,10 @@ class ReusableDropdownField extends StatelessWidget {
),
value: (value != null && value!.isNotEmpty) ? value : null,
items: [
const DropdownMenuItem<String>(
DropdownMenuItem<String>(
value: '',
child: Text('Select an option'),
child: Text(
AppLocalizations.of(context)!.selectOption),
),
...options.map<DropdownMenuItem<String>>(
(item) => DropdownMenuItem<String>(
@@ -36,6 +36,7 @@ import '../../Entity/angulardatatype/Basicp1/Basicp1_viewModel/Basicp1_view_mode
import 'package:base_project/utils/image_constant.dart';
import 'package:base_project/commans/widgets/custome_drawe_item.dart';
import 'package:base_project/l10n/app_localizations.dart';
import 'package:base_project/resources/app_colors.dart';
import 'package:base_project/routes/route_names.dart';
import 'package:base_project/utils/managers/user_manager.dart';
@@ -76,13 +77,14 @@ class MyCustomDrawer extends StatelessWidget {
height: 60,
),
),
accountName: Text("Hello, $userName"),
accountName: Text(
AppLocalizations.of(context)!.helloUser(userName)),
accountEmail: Text(email.toString()),
),
DrawerItem(
color: AppColors.primary,
icon: Icons.person,
title: 'Profile',
title: AppLocalizations.of(context)!.profile,
onTap: () {
Navigator.pushNamed(context, RouteNames.profileView);
},
@@ -90,7 +92,7 @@ class MyCustomDrawer extends StatelessWidget {
DrawerItem(
color: AppColors.primary,
icon: Icons.system_security_update,
title: 'System Parameters',
title: AppLocalizations.of(context)!.systemParameters,
onTap: () {
// Add navigation or other logic here
Navigator.pushNamed(context, RouteNames.systemParamsView);
@@ -99,7 +101,7 @@ class MyCustomDrawer extends StatelessWidget {
DrawerItem(
color: AppColors.primary,
icon: Icons.password,
title: 'change password',
title: AppLocalizations.of(context)!.changePassword,
onTap: () {
Navigator.pushNamed(context, RouteNames.changePasswordView);
},
@@ -314,7 +316,7 @@ class MyCustomDrawer extends StatelessWidget {
DrawerItem(
icon: Icons.logout,
color: Colors.red,
title: 'Logout',
title: AppLocalizations.of(context)!.logout,
onTap: () async {
await UserManager().clearUser();
Navigator.pushReplacementNamed(context, RouteNames.splashView);
@@ -0,0 +1,9 @@
import 'package:flutter/widgets.dart';
import 'package:provider/provider.dart';
import '../providers/locale_provider.dart';
/// Translates stable, server/form-builder keys with a safe English fallback.
extension DynamicStrings on BuildContext {
String trDynamic(String key) => watch<LocaleProvider>().dynamicText(key);
}
@@ -0,0 +1,55 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'dart:convert';
class LocaleProvider extends ChangeNotifier {
static const preferenceKey = 'app_locale_code';
static const supportedCodes = <String>['en', 'hi'];
Locale _locale = const Locale('en');
Locale get locale => _locale;
final Map<String, Map<String, String>> _dynamicTables = {};
Future<void> initialize() async {
final preferences = await SharedPreferences.getInstance();
final savedCode = preferences.getString(preferenceKey);
if (savedCode != null && supportedCodes.contains(savedCode)) {
_locale = Locale(savedCode);
}
await _loadDynamicTables();
notifyListeners();
}
Future<void> _loadDynamicTables() async {
for (final code in supportedCodes) {
try {
final raw = await rootBundle.loadString('assets/translations_dynamic/$code.json');
final decoded = jsonDecode(raw) as Map<String, dynamic>;
_dynamicTables[code] = decoded.map(
(key, value) => MapEntry(_normalizeKey(key), value.toString()),
);
} catch (_) {
_dynamicTables[code] = {};
}
}
}
Future<void> setLocale(String code) async {
if (!supportedCodes.contains(code) || code == _locale.languageCode) return;
_locale = Locale(code);
notifyListeners();
final preferences = await SharedPreferences.getInstance();
await preferences.setString(preferenceKey, code);
}
String dynamicText(String key) {
final normalized = _normalizeKey(key);
return _dynamicTables[_locale.languageCode]?[normalized] ??
_dynamicTables['en']?[normalized] ??
key.replaceAll('_', ' ');
}
String _normalizeKey(String key) =>
key.trim().toLowerCase().replaceAll(RegExp(r'\s+'), '_');
}
+177
View File
@@ -0,0 +1,177 @@
{
"@@locale": "en",
"appTitle": "AuthSec Flutter",
"language": "Language",
"english": "English",
"hindi": "Hindi",
"helloUser": "Hello, {name}",
"@helloUser": {"placeholders": {"name": {"type": "String"}}},
"user": "User",
"logout": "Logout",
"cancel": "Cancel",
"confirm": "Confirm",
"retry": "Retry",
"refresh": "Refresh",
"addNew": "Add new",
"searchEntity": "Search {entity}...",
"@searchEntity": {"placeholders": {"entity": {"type": "String"}}},
"loadingEntity": "Loading {entity}...",
"@loadingEntity": {"placeholders": {"entity": {"type": "String"}}},
"noEntityFound": "No {entity} found",
"@noEntityFound": {"placeholders": {"entity": {"type": "String"}}},
"addEntity": "Add {entity}",
"@addEntity": {"placeholders": {"entity": {"type": "String"}}},
"createEntity": "Create {entity}",
"@createEntity": {"placeholders": {"entity": {"type": "String"}}},
"updateEntity": "Update {entity}",
"@updateEntity": {"placeholders": {"entity": {"type": "String"}}},
"entityRequired": "{field} is required",
"@entityRequired": {"placeholders": {"field": {"type": "String"}}},
"errorLoadingData": "Error loading data",
"somethingWentWrong": "Something went wrong",
"adjustSearchTerms": "Try adjusting your search terms",
"startByAdding": "Start by adding your first {entity}",
"@startByAdding": {"placeholders": {"entity": {"type": "String"}}},
"unknown": "Unknown",
"scanBarcode": "Scan barcode",
"enterOrScanBarcode": "Enter or scan barcode",
"addAudio": "Add audio",
"selectAudioFile": "Select audio file",
"pickColor": "Pick a color",
"systemParameters": "System Parameters",
"editSystemParameters": "Edit System Parameters",
"goBack": "Go back",
"profile": "Profile",
"editProfile": "Edit profile",
"accountUpdate": "Account update",
"changePassword": "Change password",
"confirmLogout": "Confirm logout",
"confirmLogoutBody": "Are you sure you want to log out?",
"logoutAction": "Log out",
"passwordsDoNotMatch": "Passwords do not match",
"requiredField": "This field is required",
"email": "Email",
"password": "Password",
"signIn": "Sign in",
"signUp": "Sign up",
"forgotPassword": "Forgot password?",
"loading": "Loading...",
"save": "Save",
"delete": "Delete",
"edit": "Edit",
"close": "Close"
,"welcomeBack": "Welcome back!"
,"signInToContinue": "Sign in to continue to your account"
,"emailAddress": "Email address"
,"enterYourEmail": "Enter your email"
,"emailRequired": "Email is required"
,"validEmail": "Please enter a valid email"
,"enterYourPassword": "Enter your password"
,"passwordRequired": "Password is required"
,"passwordMinLength": "Password must be at least 6 characters"
,"noAccount": "Don't have an account?"
,"orContinueWith": "Or continue with"
,"verifyOtp": "Verify OTP"
,"otpSentTo": "Enter the 6-digit code sent to"
,"yourEmail": "your email"
,"enterOtp": "Enter 6-digit OTP"
,"didNotReceiveCode": "Didn't receive code?"
,"resendIn": "Resend in {seconds}s"
,"@resendIn": {"placeholders": {"seconds": {"type": "int"}}}
,"resend": "Resend"
,"dashboard": "Dashboard"
,"settings": "Settings"
,"security": "Security"
,"reports": "Reports"
,"manageAccount": "Manage your account"
,"configureSystemSettings": "Configure system settings"
,"updateYourPassword": "Update your password"
,"getOtp": "Get OTP"
,"otpEmailPrompt": "Enter your email to receive a one-time password"
,"enterEmailAddress": "Enter your email address"
,"sendOtp": "Send OTP"
,"sendingOtp": "Sending OTP..."
,"alreadyHaveAccount": "Already have an account?"
,"backToLogin": "Back to login"
,"emailLooksGood": "Email looks good"
,"invalidEmailAddress": "Invalid email address"
,"noDataAvailable": "No data available"
,"noResults": "No results"
,"clearBtn": "Clear"
,"doneBtn": "Done"
,"addFiles": "Add Files"
,"addImage": "Add Image"
,"addVideo": "Add Video"
,"insertBtn": "Insert"
,"noDataFound": "No data found"
,"sysConfigTitle": "System Configuration"
,"sysConfigSubtitle": "Configure system-wide parameters and settings"
,"generatingTheme": "Generating dynamic theme..."
,"themeApplied": "Dynamic theme applied! Colors extracted from logo."
,"themeImmediateNote": "Theme is applied immediately! Click \"Upload Logo\" to save the logo permanently to the database. The dynamic theme will work even if upload fails."
,"uploadNewLogo": "Upload New Logo"
,"removeLogo": "Remove Logo"
,"logoAlreadyUploaded": "Company logo is already uploaded and saved in the system. You can upload a new one or remove the existing logo."
,"manualOverride": "Enable Manual Override"
,"colorPrimary": "Primary"
,"colorSecondary": "Secondary"
,"colorTertiary": "Tertiary"
,"resetLogoColors": "Reset to Logo Colors"
,"resetDefault": "Reset to Default"
,"userRegistration": "User Registration"
,"allowUserRegistration": "Allow new users to register accounts"
,"themeGenerated": "Dynamic Theme Generated"
,"resetThemeTooltip": "Reset to Default Theme"
,"colorPalette": "Color Palette"
,"colorAccent1": "Accent 1"
,"colorAccent2": "Accent 2"
,"colorN": "Color {n}"
,"@colorN": {"placeholders": {"n": {"type": "String"}}}
,"themeInfo": "Theme Information"
,"totalColors": "Total Colors"
,"themeDescription": "Description"
,"warmColors": "Warm Colors"
,"coolColors": "Cool Colors"
,"neutralColors": "Neutral Colors"
,"yes": "Yes"
,"no": "No"
,"primaryButton": "Primary Button"
,"secondaryButton": "Secondary Button"
,"uploadLogo": "Upload Logo"
,"clearLogo": "Clear Logo"
,"saveConfiguration": "Save Configuration"
,"drawerHome": "Home"
,"drawerUsers": "Users"
,"drawerRoles": "Roles"
,"drawerDepartments": "Departments"
,"drawerPositions": "Positions"
,"drawerCharges": "Charges"
,"drawerWeeks": "Weeks"
,"drawerShifts": "Shifts"
,"drawerBilling": "Billing"
,"drawerEdi": "EDI Settings"
,"drawerCompany": "Company"
,"drawerLogo": "Logo"
,"registerCompany": "Register Company"
,"accCompanyName": "Company Name"
,"accCompanyHint": "Enter company name"
,"accWorkspace": "Workspace"
,"accWorkspaceHint": "Enter workspace"
,"accGst": "GST Number"
,"accGstHint": "Enter GST number"
,"accMobile": "Mobile"
,"accMobileHint": "Enter mobile number"
,"accEmailReadonly": "Email (read-only)"
,"accPan": "PAN Card"
,"accPanHint": "Enter PAN"
,"accWorking": "Working"
,"accWorkingHint": "Working status"
,"requiredVal": "Required"
,"nActive": "Active"
,"saveChanges": "Save Changes"
,"selectOption": "Select an option"
,"removeBtn": "Remove"
,"ohSnap": "Oh Snap!"
,"alertTitle": "Alert"
,"successTitle": "Success"
}
+176
View File
@@ -0,0 +1,176 @@
{
"@@locale": "hi",
"appTitle": "ऑथसेक फ्लटर",
"language": "भाषा",
"english": "अंग्रेज़ी",
"hindi": "हिन्दी",
"helloUser": "नमस्ते, {name}",
"@helloUser": {"placeholders": {"name": {"type": "String"}}},
"user": "उपयोगकर्ता",
"logout": "लॉग आउट",
"cancel": "रद्द करें",
"confirm": "पुष्टि करें",
"retry": "पुनः प्रयास करें",
"refresh": "रीफ़्रेश",
"addNew": "नया जोड़ें",
"searchEntity": "{entity} खोजें...",
"@searchEntity": {"placeholders": {"entity": {"type": "String"}}},
"loadingEntity": "{entity} लोड हो रहा है...",
"@loadingEntity": {"placeholders": {"entity": {"type": "String"}}},
"noEntityFound": "कोई {entity} नहीं मिला",
"@noEntityFound": {"placeholders": {"entity": {"type": "String"}}},
"addEntity": "{entity} जोड़ें",
"@addEntity": {"placeholders": {"entity": {"type": "String"}}},
"createEntity": "{entity} बनाएँ",
"@createEntity": {"placeholders": {"entity": {"type": "String"}}},
"updateEntity": "{entity} अपडेट करें",
"@updateEntity": {"placeholders": {"entity": {"type": "String"}}},
"entityRequired": "{field} आवश्यक है",
"@entityRequired": {"placeholders": {"field": {"type": "String"}}},
"errorLoadingData": "डेटा लोड करने में त्रुटि",
"somethingWentWrong": "कुछ गलत हो गया",
"adjustSearchTerms": "अपने खोज शब्द बदलें",
"startByAdding": "अपना पहला {entity} जोड़कर शुरू करें",
"@startByAdding": {"placeholders": {"entity": {"type": "String"}}},
"unknown": "अज्ञात",
"scanBarcode": "बारकोड स्कैन करें",
"enterOrScanBarcode": "बारकोड दर्ज करें या स्कैन करें",
"addAudio": "ऑडियो जोड़ें",
"selectAudioFile": "ऑडियो फ़ाइल चुनें",
"pickColor": "रंग चुनें",
"systemParameters": "सिस्टम पैरामीटर",
"editSystemParameters": "सिस्टम पैरामीटर संपादित करें",
"goBack": "वापस जाएँ",
"profile": "प्रोफ़ाइल",
"editProfile": "प्रोफ़ाइल संपादित करें",
"accountUpdate": "खाता अपडेट",
"changePassword": "पासवर्ड बदलें",
"confirmLogout": "लॉग आउट की पुष्टि करें",
"confirmLogoutBody": "क्या आप वाकई लॉग आउट करना चाहते हैं?",
"logoutAction": "लॉग आउट",
"passwordsDoNotMatch": "पासवर्ड मेल नहीं खाते",
"requiredField": "यह फ़ील्ड आवश्यक है",
"email": "ईमेल",
"password": "पासवर्ड",
"signIn": "साइन इन",
"signUp": "साइन अप",
"forgotPassword": "पासवर्ड भूल गए?",
"loading": "लोड हो रहा है...",
"save": "सहेजें",
"delete": "हटाएँ",
"edit": "संपादित करें",
"close": "बंद करें"
,"welcomeBack": "वापस स्वागत है!"
,"signInToContinue": "अपने खाते में जारी रखने के लिए साइन इन करें"
,"emailAddress": "ईमेल पता"
,"enterYourEmail": "अपना ईमेल दर्ज करें"
,"emailRequired": "ईमेल आवश्यक है"
,"validEmail": "कृपया मान्य ईमेल दर्ज करें"
,"enterYourPassword": "अपना पासवर्ड दर्ज करें"
,"passwordRequired": "पासवर्ड आवश्यक है"
,"passwordMinLength": "पासवर्ड कम से कम 6 वर्ण का होना चाहिए"
,"noAccount": "क्या आपका खाता नहीं है?"
,"orContinueWith": "या इसके साथ जारी रखें"
,"verifyOtp": "ओटीपी सत्यापित करें"
,"otpSentTo": "भेजा गया 6 अंकों का कोड दर्ज करें"
,"yourEmail": "आपका ईमेल"
,"enterOtp": "6 अंकों का ओटीपी दर्ज करें"
,"didNotReceiveCode": "कोड नहीं मिला?"
,"resendIn": "{seconds} सेकंड में पुनः भेजें"
,"@resendIn": {"placeholders": {"seconds": {"type": "int"}}}
,"resend": "पुनः भेजें"
,"dashboard": "डैशबोर्ड"
,"settings": "सेटिंग्स"
,"security": "सुरक्षा"
,"reports": "रिपोर्ट"
,"manageAccount": "अपने खाते का प्रबंधन करें"
,"configureSystemSettings": "सिस्टम सेटिंग्स कॉन्फ़िगर करें"
,"updateYourPassword": "अपना पासवर्ड अपडेट करें"
,"getOtp": "ओटीपी प्राप्त करें"
,"otpEmailPrompt": "वन-टाइम पासवर्ड पाने के लिए अपना ईमेल दर्ज करें"
,"enterEmailAddress": "अपना ईमेल पता दर्ज करें"
,"sendOtp": "ओटीपी भेजें"
,"sendingOtp": "ओटीपी भेजा जा रहा है..."
,"alreadyHaveAccount": "क्या आपका पहले से खाता है?"
,"backToLogin": "लॉगिन पर वापस जाएँ"
,"emailLooksGood": "ईमेल सही है"
,"invalidEmailAddress": "अमान्य ईमेल पता"
,"noDataAvailable": "कोई डेटा उपलब्ध नहीं"
,"noResults": "कोई परिणाम नहीं"
,"clearBtn": "साफ़ करें"
,"doneBtn": "हो गया"
,"addFiles": "फ़ाइलें जोड़ें"
,"addImage": "छवि जोड़ें"
,"addVideo": "वीडियो जोड़ें"
,"insertBtn": "डालें"
,"noDataFound": "कोई डेटा नहीं मिला"
,"sysConfigTitle": "सिस्टम कॉन्फ़िगरेशन"
,"sysConfigSubtitle": "सिस्टम-व्यापी पैरामीटर और सेटिंग्स कॉन्फ़िगर करें"
,"generatingTheme": "डायनामिक थीम बनाई जा रही है..."
,"themeApplied": "डायनामिक थीम लागू! लोगो से रंग निकाले गए।"
,"themeImmediateNote": "थीम तुरंत लागू होती है! लोगो को डेटाबेस में स्थायी रूप से सहेजने के लिए अपलोड लोगो पर क्लिक करें। अपलोड विफल होने पर भी डायनामिक थीम काम करेगी।"
,"uploadNewLogo": "नया लोगो अपलोड करें"
,"removeLogo": "लोगो हटाएं"
,"logoAlreadyUploaded": "कंपनी का लोगो पहले से अपलोड है और सिस्टम में सहेजा गया है। आप नया अपलोड कर सकते हैं या मौजूदा लोगो हटा सकते हैं।"
,"manualOverride": "मैन्युअल ओवरराइड सक्षम करें"
,"colorPrimary": "प्राथमिक"
,"colorSecondary": "द्वितीयक"
,"colorTertiary": "तृतीयक"
,"resetLogoColors": "लोगो रंगों पर रीसेट करें"
,"resetDefault": "डिफ़ॉल्ट पर रीसेट करें"
,"userRegistration": "उपयोगकर्ता पंजीकरण"
,"allowUserRegistration": "नए उपयोगकर्ताओं को खाते पंजीकृत करने दें"
,"themeGenerated": "डायनामिक थीम बनाई गई"
,"resetThemeTooltip": "डिफ़ॉल्ट थीम पर रीसेट करें"
,"colorPalette": "रंग पट्टिका"
,"colorAccent1": "एक्सेंट 1"
,"colorAccent2": "एक्सेंट 2"
,"colorN": "रंग {n}"
,"themeInfo": "थीम जानकारी"
,"totalColors": "कुल रंग"
,"themeDescription": "विवरण"
,"warmColors": "गर्म रंग"
,"coolColors": "ठंडे रंग"
,"neutralColors": "तटस्थ रंग"
,"yes": "हां"
,"no": "नहीं"
,"primaryButton": "प्राथमिक बटन"
,"secondaryButton": "द्वितीयक बटन"
,"uploadLogo": "लोगो अपलोड करें"
,"clearLogo": "लोगो साफ़ करें"
,"saveConfiguration": "कॉन्फ़िगरेशन सहेजें"
,"drawerHome": "होम"
,"drawerUsers": "उपयोगकर्ता"
,"drawerRoles": "भूमिकाएं"
,"drawerDepartments": "विभाग"
,"drawerPositions": "पद"
,"drawerCharges": "शुल्क"
,"drawerWeeks": "सप्ताह"
,"drawerShifts": "पारियां"
,"drawerBilling": "बिलिंग"
,"drawerEdi": "EDI सेटिंग्स"
,"drawerCompany": "कंपनी"
,"drawerLogo": "लोगो"
,"registerCompany": "कंपनी पंजीकृत करें"
,"accCompanyName": "कंपनी का नाम"
,"accCompanyHint": "कंपनी का नाम दर्ज करें"
,"accWorkspace": "कार्यक्षेत्र"
,"accWorkspaceHint": "कार्यक्षेत्र दर्ज करें"
,"accGst": "जीएसटी नंबर"
,"accGstHint": "जीएसटी नंबर दर्ज करें"
,"accMobile": "मोबाइल"
,"accMobileHint": "मोबाइल नंबर दर्ज करें"
,"accEmailReadonly": "ईमेल (केवल-पठन)"
,"accPan": "पैन कार्ड"
,"accPanHint": "पैन दर्ज करें"
,"accWorking": "कार्य"
,"accWorkingHint": "कार्य स्थिति"
,"requiredVal": "आवश्यक"
,"nActive": "सक्रिय"
,"saveChanges": "परिवर्तन सहेजें"
,"selectOption": "एक विकल्प चुनें"
,"removeBtn": "हटाएं"
,"ohSnap": "ओह स्नैप!"
,"alertTitle": "चेतावनी"
,"successTitle": "सफलता"
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,526 @@
// ignore: unused_import
import 'package:intl/intl.dart' as intl;
import 'app_localizations.dart';
// ignore_for_file: type=lint
/// The translations for English (`en`).
class AppLocalizationsEn extends AppLocalizations {
AppLocalizationsEn([String locale = 'en']) : super(locale);
@override
String get appTitle => 'AuthSec Flutter';
@override
String get language => 'Language';
@override
String get english => 'English';
@override
String get hindi => 'Hindi';
@override
String helloUser(String name) {
return 'Hello, $name';
}
@override
String get user => 'User';
@override
String get logout => 'Logout';
@override
String get cancel => 'Cancel';
@override
String get confirm => 'Confirm';
@override
String get retry => 'Retry';
@override
String get refresh => 'Refresh';
@override
String get addNew => 'Add new';
@override
String searchEntity(String entity) {
return 'Search $entity...';
}
@override
String loadingEntity(String entity) {
return 'Loading $entity...';
}
@override
String noEntityFound(String entity) {
return 'No $entity found';
}
@override
String addEntity(String entity) {
return 'Add $entity';
}
@override
String createEntity(String entity) {
return 'Create $entity';
}
@override
String updateEntity(String entity) {
return 'Update $entity';
}
@override
String entityRequired(String field) {
return '$field is required';
}
@override
String get errorLoadingData => 'Error loading data';
@override
String get somethingWentWrong => 'Something went wrong';
@override
String get adjustSearchTerms => 'Try adjusting your search terms';
@override
String startByAdding(String entity) {
return 'Start by adding your first $entity';
}
@override
String get unknown => 'Unknown';
@override
String get scanBarcode => 'Scan barcode';
@override
String get enterOrScanBarcode => 'Enter or scan barcode';
@override
String get addAudio => 'Add audio';
@override
String get selectAudioFile => 'Select audio file';
@override
String get pickColor => 'Pick a color';
@override
String get systemParameters => 'System Parameters';
@override
String get editSystemParameters => 'Edit System Parameters';
@override
String get goBack => 'Go back';
@override
String get profile => 'Profile';
@override
String get editProfile => 'Edit profile';
@override
String get accountUpdate => 'Account update';
@override
String get changePassword => 'Change password';
@override
String get confirmLogout => 'Confirm logout';
@override
String get confirmLogoutBody => 'Are you sure you want to log out?';
@override
String get logoutAction => 'Log out';
@override
String get passwordsDoNotMatch => 'Passwords do not match';
@override
String get requiredField => 'This field is required';
@override
String get email => 'Email';
@override
String get password => 'Password';
@override
String get signIn => 'Sign in';
@override
String get signUp => 'Sign up';
@override
String get forgotPassword => 'Forgot password?';
@override
String get loading => 'Loading...';
@override
String get save => 'Save';
@override
String get delete => 'Delete';
@override
String get edit => 'Edit';
@override
String get close => 'Close';
@override
String get welcomeBack => 'Welcome back!';
@override
String get signInToContinue => 'Sign in to continue to your account';
@override
String get emailAddress => 'Email address';
@override
String get enterYourEmail => 'Enter your email';
@override
String get emailRequired => 'Email is required';
@override
String get validEmail => 'Please enter a valid email';
@override
String get enterYourPassword => 'Enter your password';
@override
String get passwordRequired => 'Password is required';
@override
String get passwordMinLength => 'Password must be at least 6 characters';
@override
String get noAccount => 'Don\'t have an account?';
@override
String get orContinueWith => 'Or continue with';
@override
String get verifyOtp => 'Verify OTP';
@override
String get otpSentTo => 'Enter the 6-digit code sent to';
@override
String get yourEmail => 'your email';
@override
String get enterOtp => 'Enter 6-digit OTP';
@override
String get didNotReceiveCode => 'Didn\'t receive code?';
@override
String resendIn(int seconds) {
return 'Resend in ${seconds}s';
}
@override
String get resend => 'Resend';
@override
String get dashboard => 'Dashboard';
@override
String get settings => 'Settings';
@override
String get security => 'Security';
@override
String get reports => 'Reports';
@override
String get manageAccount => 'Manage your account';
@override
String get configureSystemSettings => 'Configure system settings';
@override
String get updateYourPassword => 'Update your password';
@override
String get getOtp => 'Get OTP';
@override
String get otpEmailPrompt =>
'Enter your email to receive a one-time password';
@override
String get enterEmailAddress => 'Enter your email address';
@override
String get sendOtp => 'Send OTP';
@override
String get sendingOtp => 'Sending OTP...';
@override
String get alreadyHaveAccount => 'Already have an account?';
@override
String get backToLogin => 'Back to login';
@override
String get emailLooksGood => 'Email looks good';
@override
String get invalidEmailAddress => 'Invalid email address';
@override
String get noDataAvailable => 'No data available';
@override
String get noResults => 'No results';
@override
String get clearBtn => 'Clear';
@override
String get doneBtn => 'Done';
@override
String get addFiles => 'Add Files';
@override
String get addImage => 'Add Image';
@override
String get addVideo => 'Add Video';
@override
String get insertBtn => 'Insert';
@override
String get noDataFound => 'No data found';
@override
String get sysConfigTitle => 'System Configuration';
@override
String get sysConfigSubtitle =>
'Configure system-wide parameters and settings';
@override
String get generatingTheme => 'Generating dynamic theme...';
@override
String get themeApplied =>
'Dynamic theme applied! Colors extracted from logo.';
@override
String get themeImmediateNote =>
'Theme is applied immediately! Click \"Upload Logo\" to save the logo permanently to the database. The dynamic theme will work even if upload fails.';
@override
String get uploadNewLogo => 'Upload New Logo';
@override
String get removeLogo => 'Remove Logo';
@override
String get logoAlreadyUploaded =>
'Company logo is already uploaded and saved in the system. You can upload a new one or remove the existing logo.';
@override
String get manualOverride => 'Enable Manual Override';
@override
String get colorPrimary => 'Primary';
@override
String get colorSecondary => 'Secondary';
@override
String get colorTertiary => 'Tertiary';
@override
String get resetLogoColors => 'Reset to Logo Colors';
@override
String get resetDefault => 'Reset to Default';
@override
String get userRegistration => 'User Registration';
@override
String get allowUserRegistration => 'Allow new users to register accounts';
@override
String get themeGenerated => 'Dynamic Theme Generated';
@override
String get resetThemeTooltip => 'Reset to Default Theme';
@override
String get colorPalette => 'Color Palette';
@override
String get colorAccent1 => 'Accent 1';
@override
String get colorAccent2 => 'Accent 2';
@override
String colorN(String n) {
return 'Color $n';
}
@override
String get themeInfo => 'Theme Information';
@override
String get totalColors => 'Total Colors';
@override
String get themeDescription => 'Description';
@override
String get warmColors => 'Warm Colors';
@override
String get coolColors => 'Cool Colors';
@override
String get neutralColors => 'Neutral Colors';
@override
String get yes => 'Yes';
@override
String get no => 'No';
@override
String get primaryButton => 'Primary Button';
@override
String get secondaryButton => 'Secondary Button';
@override
String get uploadLogo => 'Upload Logo';
@override
String get clearLogo => 'Clear Logo';
@override
String get saveConfiguration => 'Save Configuration';
@override
String get drawerHome => 'Home';
@override
String get drawerUsers => 'Users';
@override
String get drawerRoles => 'Roles';
@override
String get drawerDepartments => 'Departments';
@override
String get drawerPositions => 'Positions';
@override
String get drawerCharges => 'Charges';
@override
String get drawerWeeks => 'Weeks';
@override
String get drawerShifts => 'Shifts';
@override
String get drawerBilling => 'Billing';
@override
String get drawerEdi => 'EDI Settings';
@override
String get drawerCompany => 'Company';
@override
String get drawerLogo => 'Logo';
@override
String get registerCompany => 'Register Company';
@override
String get accCompanyName => 'Company Name';
@override
String get accCompanyHint => 'Enter company name';
@override
String get accWorkspace => 'Workspace';
@override
String get accWorkspaceHint => 'Enter workspace';
@override
String get accGst => 'GST Number';
@override
String get accGstHint => 'Enter GST number';
@override
String get accMobile => 'Mobile';
@override
String get accMobileHint => 'Enter mobile number';
@override
String get accEmailReadonly => 'Email (read-only)';
@override
String get accPan => 'PAN Card';
@override
String get accPanHint => 'Enter PAN';
@override
String get accWorking => 'Working';
@override
String get accWorkingHint => 'Working status';
@override
String get requiredVal => 'Required';
@override
String get nActive => 'Active';
@override
String get saveChanges => 'Save Changes';
@override
String get selectOption => 'Select an option';
@override
String get removeBtn => 'Remove';
@override
String get ohSnap => 'Oh Snap!';
@override
String get alertTitle => 'Alert';
@override
String get successTitle => 'Success';
}
@@ -0,0 +1,526 @@
// ignore: unused_import
import 'package:intl/intl.dart' as intl;
import 'app_localizations.dart';
// ignore_for_file: type=lint
/// The translations for Hindi (`hi`).
class AppLocalizationsHi extends AppLocalizations {
AppLocalizationsHi([String locale = 'hi']) : super(locale);
@override
String get appTitle => 'ऑथसेक फ्लटर';
@override
String get language => 'भाषा';
@override
String get english => 'अंग्रेज़ी';
@override
String get hindi => 'हिन्दी';
@override
String helloUser(String name) {
return 'नमस्ते, $name';
}
@override
String get user => 'उपयोगकर्ता';
@override
String get logout => 'लॉग आउट';
@override
String get cancel => 'रद्द करें';
@override
String get confirm => 'पुष्टि करें';
@override
String get retry => 'पुनः प्रयास करें';
@override
String get refresh => 'रीफ़्रेश';
@override
String get addNew => 'नया जोड़ें';
@override
String searchEntity(String entity) {
return '$entity खोजें...';
}
@override
String loadingEntity(String entity) {
return '$entity लोड हो रहा है...';
}
@override
String noEntityFound(String entity) {
return 'कोई $entity नहीं मिला';
}
@override
String addEntity(String entity) {
return '$entity जोड़ें';
}
@override
String createEntity(String entity) {
return '$entity बनाएँ';
}
@override
String updateEntity(String entity) {
return '$entity अपडेट करें';
}
@override
String entityRequired(String field) {
return '$field आवश्यक है';
}
@override
String get errorLoadingData => 'डेटा लोड करने में त्रुटि';
@override
String get somethingWentWrong => 'कुछ गलत हो गया';
@override
String get adjustSearchTerms => 'अपने खोज शब्द बदलें';
@override
String startByAdding(String entity) {
return 'अपना पहला $entity जोड़कर शुरू करें';
}
@override
String get unknown => 'अज्ञात';
@override
String get scanBarcode => 'बारकोड स्कैन करें';
@override
String get enterOrScanBarcode => 'बारकोड दर्ज करें या स्कैन करें';
@override
String get addAudio => 'ऑडियो जोड़ें';
@override
String get selectAudioFile => 'ऑडियो फ़ाइल चुनें';
@override
String get pickColor => 'रंग चुनें';
@override
String get systemParameters => 'सिस्टम पैरामीटर';
@override
String get editSystemParameters => 'सिस्टम पैरामीटर संपादित करें';
@override
String get goBack => 'वापस जाएँ';
@override
String get profile => 'प्रोफ़ाइल';
@override
String get editProfile => 'प्रोफ़ाइल संपादित करें';
@override
String get accountUpdate => 'खाता अपडेट';
@override
String get changePassword => 'पासवर्ड बदलें';
@override
String get confirmLogout => 'लॉग आउट की पुष्टि करें';
@override
String get confirmLogoutBody => 'क्या आप वाकई लॉग आउट करना चाहते हैं?';
@override
String get logoutAction => 'लॉग आउट';
@override
String get passwordsDoNotMatch => 'पासवर्ड मेल नहीं खाते';
@override
String get requiredField => 'यह फ़ील्ड आवश्यक है';
@override
String get email => 'ईमेल';
@override
String get password => 'पासवर्ड';
@override
String get signIn => 'साइन इन';
@override
String get signUp => 'साइन अप';
@override
String get forgotPassword => 'पासवर्ड भूल गए?';
@override
String get loading => 'लोड हो रहा है...';
@override
String get save => 'सहेजें';
@override
String get delete => 'हटाएँ';
@override
String get edit => 'संपादित करें';
@override
String get close => 'बंद करें';
@override
String get welcomeBack => 'वापस स्वागत है!';
@override
String get signInToContinue => 'अपने खाते में जारी रखने के लिए साइन इन करें';
@override
String get emailAddress => 'ईमेल पता';
@override
String get enterYourEmail => 'अपना ईमेल दर्ज करें';
@override
String get emailRequired => 'ईमेल आवश्यक है';
@override
String get validEmail => 'कृपया मान्य ईमेल दर्ज करें';
@override
String get enterYourPassword => 'अपना पासवर्ड दर्ज करें';
@override
String get passwordRequired => 'पासवर्ड आवश्यक है';
@override
String get passwordMinLength => 'पासवर्ड कम से कम 6 वर्ण का होना चाहिए';
@override
String get noAccount => 'क्या आपका खाता नहीं है?';
@override
String get orContinueWith => 'या इसके साथ जारी रखें';
@override
String get verifyOtp => 'ओटीपी सत्यापित करें';
@override
String get otpSentTo => 'भेजा गया 6 अंकों का कोड दर्ज करें';
@override
String get yourEmail => 'आपका ईमेल';
@override
String get enterOtp => '6 अंकों का ओटीपी दर्ज करें';
@override
String get didNotReceiveCode => 'कोड नहीं मिला?';
@override
String resendIn(int seconds) {
return '$seconds सेकंड में पुनः भेजें';
}
@override
String get resend => 'पुनः भेजें';
@override
String get dashboard => 'डैशबोर्ड';
@override
String get settings => 'सेटिंग्स';
@override
String get security => 'सुरक्षा';
@override
String get reports => 'रिपोर्ट';
@override
String get manageAccount => 'अपने खाते का प्रबंधन करें';
@override
String get configureSystemSettings => 'सिस्टम सेटिंग्स कॉन्फ़िगर करें';
@override
String get updateYourPassword => 'अपना पासवर्ड अपडेट करें';
@override
String get getOtp => 'ओटीपी प्राप्त करें';
@override
String get otpEmailPrompt =>
'वन-टाइम पासवर्ड पाने के लिए अपना ईमेल दर्ज करें';
@override
String get enterEmailAddress => 'अपना ईमेल पता दर्ज करें';
@override
String get sendOtp => 'ओटीपी भेजें';
@override
String get sendingOtp => 'ओटीपी भेजा जा रहा है...';
@override
String get alreadyHaveAccount => 'क्या आपका पहले से खाता है?';
@override
String get backToLogin => 'लॉगिन पर वापस जाएँ';
@override
String get emailLooksGood => 'ईमेल सही है';
@override
String get invalidEmailAddress => 'अमान्य ईमेल पता';
@override
String get noDataAvailable => 'कोई डेटा उपलब्ध नहीं';
@override
String get noResults => 'कोई परिणाम नहीं';
@override
String get clearBtn => 'साफ़ करें';
@override
String get doneBtn => 'हो गया';
@override
String get addFiles => 'फ़ाइलें जोड़ें';
@override
String get addImage => 'छवि जोड़ें';
@override
String get addVideo => 'वीडियो जोड़ें';
@override
String get insertBtn => 'डालें';
@override
String get noDataFound => 'कोई डेटा नहीं मिला';
@override
String get sysConfigTitle => 'सिस्टम कॉन्फ़िगरेशन';
@override
String get sysConfigSubtitle =>
'सिस्टम-व्यापी पैरामीटर और सेटिंग्स कॉन्फ़िगर करें';
@override
String get generatingTheme => 'डायनामिक थीम बनाई जा रही है...';
@override
String get themeApplied => 'डायनामिक थीम लागू! लोगो से रंग निकाले गए।';
@override
String get themeImmediateNote =>
'थीम तुरंत लागू होती है! लोगो को डेटाबेस में स्थायी रूप से सहेजने के लिए अपलोड लोगो पर क्लिक करें। अपलोड विफल होने पर भी डायनामिक थीम काम करेगी।';
@override
String get uploadNewLogo => 'नया लोगो अपलोड करें';
@override
String get removeLogo => 'लोगो हटाएं';
@override
String get logoAlreadyUploaded =>
'कंपनी का लोगो पहले से अपलोड है और सिस्टम में सहेजा गया है। आप नया अपलोड कर सकते हैं या मौजूदा लोगो हटा सकते हैं।';
@override
String get manualOverride => 'मैन्युअल ओवरराइड सक्षम करें';
@override
String get colorPrimary => 'प्राथमिक';
@override
String get colorSecondary => 'द्वितीयक';
@override
String get colorTertiary => 'तृतीयक';
@override
String get resetLogoColors => 'लोगो रंगों पर रीसेट करें';
@override
String get resetDefault => 'डिफ़ॉल्ट पर रीसेट करें';
@override
String get userRegistration => 'उपयोगकर्ता पंजीकरण';
@override
String get allowUserRegistration =>
'नए उपयोगकर्ताओं को खाते पंजीकृत करने दें';
@override
String get themeGenerated => 'डायनामिक थीम बनाई गई';
@override
String get resetThemeTooltip => 'डिफ़ॉल्ट थीम पर रीसेट करें';
@override
String get colorPalette => 'रंग पट्टिका';
@override
String get colorAccent1 => 'एक्सेंट 1';
@override
String get colorAccent2 => 'एक्सेंट 2';
@override
String colorN(String n) {
return 'रंग $n';
}
@override
String get themeInfo => 'थीम जानकारी';
@override
String get totalColors => 'कुल रंग';
@override
String get themeDescription => 'विवरण';
@override
String get warmColors => 'गर्म रंग';
@override
String get coolColors => 'ठंडे रंग';
@override
String get neutralColors => 'तटस्थ रंग';
@override
String get yes => 'हां';
@override
String get no => 'नहीं';
@override
String get primaryButton => 'प्राथमिक बटन';
@override
String get secondaryButton => 'द्वितीयक बटन';
@override
String get uploadLogo => 'लोगो अपलोड करें';
@override
String get clearLogo => 'लोगो साफ़ करें';
@override
String get saveConfiguration => 'कॉन्फ़िगरेशन सहेजें';
@override
String get drawerHome => 'होम';
@override
String get drawerUsers => 'उपयोगकर्ता';
@override
String get drawerRoles => 'भूमिकाएं';
@override
String get drawerDepartments => 'विभाग';
@override
String get drawerPositions => 'पद';
@override
String get drawerCharges => 'शुल्क';
@override
String get drawerWeeks => 'सप्ताह';
@override
String get drawerShifts => 'पारियां';
@override
String get drawerBilling => 'बिलिंग';
@override
String get drawerEdi => 'EDI सेटिंग्स';
@override
String get drawerCompany => 'कंपनी';
@override
String get drawerLogo => 'लोगो';
@override
String get registerCompany => 'कंपनी पंजीकृत करें';
@override
String get accCompanyName => 'कंपनी का नाम';
@override
String get accCompanyHint => 'कंपनी का नाम दर्ज करें';
@override
String get accWorkspace => 'कार्यक्षेत्र';
@override
String get accWorkspaceHint => 'कार्यक्षेत्र दर्ज करें';
@override
String get accGst => 'जीएसटी नंबर';
@override
String get accGstHint => 'जीएसटी नंबर दर्ज करें';
@override
String get accMobile => 'मोबाइल';
@override
String get accMobileHint => 'मोबाइल नंबर दर्ज करें';
@override
String get accEmailReadonly => 'ईमेल (केवल-पठन)';
@override
String get accPan => 'पैन कार्ड';
@override
String get accPanHint => 'पैन दर्ज करें';
@override
String get accWorking => 'कार्य';
@override
String get accWorkingHint => 'कार्य स्थिति';
@override
String get requiredVal => 'आवश्यक';
@override
String get nActive => 'सक्रिय';
@override
String get saveChanges => 'परिवर्तन सहेजें';
@override
String get selectOption => 'एक विकल्प चुनें';
@override
String get removeBtn => 'हटाएं';
@override
String get ohSnap => 'ओह स्नैप!';
@override
String get alertTitle => 'चेतावनी';
@override
String get successTitle => 'सफलता';
}
+10 -2
View File
@@ -7,14 +7,18 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
import 'core/providers/dynamic_theme_provider.dart';
import 'core/providers/locale_provider.dart';
import 'core/providers/theme_provider.dart';
import 'core/theme/app_theme.dart';
import 'l10n/app_localizations.dart';
import 'routes/app_routes.dart';
import 'utils/managers/user_manager.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await UserManager().initialize();
final localeProvider = LocaleProvider();
await localeProvider.initialize();
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
runApp(MultiProvider(
@@ -24,6 +28,7 @@ void main() async {
ChangeNotifierProvider(create: (context) => SystemParamsViewModel()),
ChangeNotifierProvider(create: (context) => ThemeProvider()),
ChangeNotifierProvider(create: (context) => DynamicThemeProvider()),
ChangeNotifierProvider.value(value: localeProvider),
],
child: const MyApp(),
));
@@ -63,8 +68,8 @@ class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Consumer2<ThemeProvider, DynamicThemeProvider>(
builder: (context, themeProvider, dynamicThemeProvider, child) {
return Consumer3<ThemeProvider, DynamicThemeProvider, LocaleProvider>(
builder: (context, themeProvider, dynamicThemeProvider, localeProvider, child) {
final theme = AppTheme.getTheme(context);
// Set system UI overlay style
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
@@ -86,6 +91,9 @@ class MyApp extends StatelessWidget {
initialRoute: RouteNames.splashView,
onGenerateRoute: AppRoutes.generateRoutes,
navigatorKey: navigatorKey,
locale: localeProvider.locale,
supportedLocales: AppLocalizations.supportedLocales,
localizationsDelegates: AppLocalizations.localizationsDelegates,
builder: (context, child) {
return MediaQuery(
data: MediaQuery.of(context).copyWith(
@@ -1,5 +1,6 @@
import 'dart:io';
import 'dart:typed_data';
import 'package:base_project/l10n/app_localizations.dart';
import 'package:flutter/material.dart';
import '../../../core/constants/ui_constants.dart';
import '../buttons/modern_button.dart';
@@ -208,7 +209,7 @@ class _ModernImagePickerState extends State<ModernImagePicker>
if (hasImage && widget.onRemoveImage != null) ...[
const SizedBox(width: UIConstants.spacing12),
ModernButton(
text: 'Remove',
text: AppLocalizations.of(context)!.removeBtn,
type: ModernButtonType.danger,
size: ModernButtonSize.medium,
icon: Icon(Icons.delete_outline),
@@ -0,0 +1,28 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../core/providers/locale_provider.dart';
import '../../l10n/app_localizations.dart';
class LanguageSwitcher extends StatelessWidget {
const LanguageSwitcher({super.key});
@override
Widget build(BuildContext context) {
final locale = context.watch<LocaleProvider>().locale.languageCode;
final strings = AppLocalizations.of(context)!;
return DropdownButtonHideUnderline(
child: DropdownButton<String>(
value: locale,
icon: const Icon(Icons.language),
onChanged: (code) {
if (code != null) context.read<LocaleProvider>().setLocale(code);
},
items: [
DropdownMenuItem(value: 'en', child: Text(strings.english)),
DropdownMenuItem(value: 'hi', child: Text(strings.hindi)),
],
),
);
}
}
@@ -1,9 +1,11 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../../core/constants/ui_constants.dart';
import '../../../l10n/app_localizations.dart';
import '../../../utils/managers/user_manager.dart';
import '../../../view_model/profile/profile_view_model.dart';
import '../buttons/modern_button.dart';
import '../language_switcher.dart';
class ModernDrawer extends StatelessWidget {
final List<DrawerItem> items;
@@ -52,6 +54,17 @@ class ModernDrawer extends StatelessWidget {
// Footer
if (footer != null) footer!,
Padding(
padding: const EdgeInsets.symmetric(horizontal: UIConstants.spacing24),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(AppLocalizations.of(context)!.language),
const LanguageSwitcher(),
],
),
),
// Logout Section
_buildLogoutSection(context, theme, colorScheme),
],
@@ -122,7 +135,8 @@ class ModernDrawer extends StatelessWidget {
// User Name
Text(
"Hello, ${userName ?? 'User'}",
AppLocalizations.of(context)!
.helloUser(userName ?? AppLocalizations.of(context)!.user),
style: theme.textTheme.titleLarge?.copyWith(
color: Colors.white,
fontWeight: FontWeight.w600,
@@ -216,7 +230,7 @@ class ModernDrawer extends StatelessWidget {
return Container(
padding: const EdgeInsets.all(UIConstants.spacing24),
child: ModernButton(
text: 'Logout',
text: AppLocalizations.of(context)!.logout,
type: ModernButtonType.danger,
size: ModernButtonSize.medium,
icon: Icon(Icons.logout),
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../core/constants/ui_constants.dart';
import '../../core/providers/dynamic_theme_provider.dart';
import '../../l10n/app_localizations.dart';
class ThemePreview extends StatelessWidget {
const ThemePreview({super.key});
@@ -56,7 +57,7 @@ class ThemePreview extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Dynamic Theme Generated',
AppLocalizations.of(context)!.themeGenerated,
style:
Theme.of(context).textTheme.titleLarge?.copyWith(
color: colorScheme.onSurface,
@@ -79,7 +80,8 @@ class ThemePreview extends StatelessWidget {
Icons.refresh,
color: colorScheme.primary,
),
tooltip: 'Reset to Default Theme',
tooltip: AppLocalizations.of(context)!
.resetThemeTooltip,
),
],
),
@@ -88,7 +90,7 @@ class ThemePreview extends StatelessWidget {
// Color Palette
Text(
'Color Palette',
AppLocalizations.of(context)!.colorPalette,
style: Theme.of(context).textTheme.titleMedium?.copyWith(
color: colorScheme.onSurface,
fontWeight: FontWeight.w600,
@@ -103,11 +105,11 @@ class ThemePreview extends StatelessWidget {
children: logoColors.take(5).map((color) {
final index = logoColors.indexOf(color);
final labels = [
'Primary',
'Secondary',
'Tertiary',
'Accent 1',
'Accent 2'
AppLocalizations.of(context)!.colorPrimary,
AppLocalizations.of(context)!.colorSecondary,
AppLocalizations.of(context)!.colorTertiary,
AppLocalizations.of(context)!.colorAccent1,
AppLocalizations.of(context)!.colorAccent2
];
return Column(
@@ -142,7 +144,8 @@ class ThemePreview extends StatelessWidget {
Text(
index < labels.length
? labels[index]
: 'Color ${index + 1}',
: AppLocalizations.of(context)!
.colorN((index + 1).toString()),
style: Theme.of(context).textTheme.bodySmall?.copyWith(
color: colorScheme.onSurfaceVariant,
fontWeight: FontWeight.w500,
@@ -169,7 +172,7 @@ class ThemePreview extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Theme Information',
AppLocalizations.of(context)!.themeInfo,
style: Theme.of(context).textTheme.titleSmall?.copyWith(
color: colorScheme.onSurface,
fontWeight: FontWeight.w600,
@@ -177,24 +180,27 @@ class ThemePreview extends StatelessWidget {
),
const SizedBox(height: UIConstants.spacing8),
_buildInfoRow(
'Total Colors', '${paletteInfo['totalColors']}'),
_buildInfoRow('Description', paletteInfo['description']),
AppLocalizations.of(context)!.totalColors,
'${paletteInfo['totalColors']}'),
_buildInfoRow(
AppLocalizations.of(context)!.themeDescription,
paletteInfo['description']),
if (paletteInfo['characteristics'] != null) ...[
_buildInfoRow(
'Warm Colors',
AppLocalizations.of(context)!.warmColors,
paletteInfo['characteristics']['warm']
? 'Yes'
: 'No'),
? AppLocalizations.of(context)!.yes
: AppLocalizations.of(context)!.no),
_buildInfoRow(
'Cool Colors',
AppLocalizations.of(context)!.coolColors,
paletteInfo['characteristics']['cool']
? 'Yes'
: 'No'),
? AppLocalizations.of(context)!.yes
: AppLocalizations.of(context)!.no),
_buildInfoRow(
'Neutral Colors',
AppLocalizations.of(context)!.neutralColors,
paletteInfo['characteristics']['neutral']
? 'Yes'
: 'No'),
? AppLocalizations.of(context)!.yes
: AppLocalizations.of(context)!.no),
],
],
),
@@ -216,7 +222,8 @@ class ThemePreview extends StatelessWidget {
BorderRadius.circular(UIConstants.radius12),
),
),
child: const Text('Primary Button'),
child: Text(AppLocalizations.of(context)!
.primaryButton),
),
),
const SizedBox(width: UIConstants.spacing12),
@@ -231,7 +238,8 @@ class ThemePreview extends StatelessWidget {
BorderRadius.circular(UIConstants.radius12),
),
),
child: const Text('Secondary Button'),
child: Text(AppLocalizations.of(context)!
.secondaryButton),
),
),
],
@@ -2,6 +2,7 @@ import 'package:base_project/commans/widgets/custom_textform_field.dart';
import 'package:base_project/commans/widgets/custome_elevated_button.dart';
import 'package:base_project/core/constants/ui_constants.dart';
import 'package:base_project/core/providers/dynamic_theme_provider.dart';
import 'package:base_project/l10n/app_localizations.dart';
import 'package:base_project/utils/validator/text_feild_validator.dart';
import 'package:base_project/view/auth/sign_up_view.dart';
import 'package:base_project/view_model/auth/auth_view_model.dart';
@@ -231,7 +232,8 @@ class _AdminRegViewState extends State<AdminRegView>
builder: (context, provider, child) {
return MyCustomElevatedButton(
isLoading: provider.isLoading,
child: const Text("Register Company"),
child: Text(AppLocalizations.of(context)!
.registerCompany),
onPressed: () async {
if (_formKey.currentState!.validate()) {
final Map<String, dynamic> signUpData = {
+16 -11
View File
@@ -9,6 +9,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../l10n/app_localizations.dart';
class GetOtpView extends StatefulWidget {
const GetOtpView({super.key});
@@ -483,7 +484,7 @@ class _GetOtpViewState extends State<GetOtpView> with TickerProviderStateMixin {
child: Column(
children: [
Text(
'Get OTP',
AppLocalizations.of(context)!.getOtp,
style: Theme.of(context).textTheme.headlineMedium?.copyWith(
color: colorScheme.primary,
fontWeight: FontWeight.w700,
@@ -493,7 +494,7 @@ class _GetOtpViewState extends State<GetOtpView> with TickerProviderStateMixin {
),
const SizedBox(height: UIConstants.spacing12),
Text(
'Enter your email to receive a one-time password',
AppLocalizations.of(context)!.otpEmailPrompt,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: colorScheme.onSurface.withOpacity(0.8),
fontWeight: FontWeight.w400,
@@ -543,8 +544,8 @@ class _GetOtpViewState extends State<GetOtpView> with TickerProviderStateMixin {
children: [
// Email Field
_buildEnhancedTextField(
label: 'Email Address',
hint: 'Enter your email address',
label: AppLocalizations.of(context)!.emailAddress,
hint: AppLocalizations.of(context)!.enterEmailAddress,
controller: _emailController,
focusNode: _emailFocusNode,
keyboardType: TextInputType.emailAddress,
@@ -554,12 +555,12 @@ class _GetOtpViewState extends State<GetOtpView> with TickerProviderStateMixin {
textInputAction: TextInputAction.done,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Email is required';
return AppLocalizations.of(context)!.emailRequired;
}
if (!RegExp(
r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$')
.hasMatch(value)) {
return 'Please enter a valid email';
return AppLocalizations.of(context)!.validEmail;
}
return null;
},
@@ -847,7 +848,9 @@ class _GetOtpViewState extends State<GetOtpView> with TickerProviderStateMixin {
) ??
const TextStyle(),
child: Text(
isLoading ? 'Sending OTP...' : 'Send OTP',
isLoading
? AppLocalizations.of(context)!.sendingOtp
: AppLocalizations.of(context)!.sendOtp,
),
);
}
@@ -919,7 +922,7 @@ class _GetOtpViewState extends State<GetOtpView> with TickerProviderStateMixin {
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Already have an account? ",
'${AppLocalizations.of(context)!.alreadyHaveAccount} ',
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Colors.grey.shade700,
fontWeight: FontWeight.w500,
@@ -928,7 +931,7 @@ class _GetOtpViewState extends State<GetOtpView> with TickerProviderStateMixin {
TextButton(
onPressed: () => Navigator.pop(context),
child: Text(
'Back to Login',
AppLocalizations.of(context)!.backToLogin,
style: Theme.of(context).textTheme.labelLarge?.copyWith(
color: colorScheme.primary,
fontWeight: FontWeight.w700,
@@ -982,8 +985,10 @@ class _GetOtpViewState extends State<GetOtpView> with TickerProviderStateMixin {
? Icons.info_outline
: (_isEmailValid ? Icons.check_circle : Icons.error_outline);
final msg = _emailController.text.isEmpty
? 'Enter your email address'
: (_isEmailValid ? 'Email looks good' : 'Invalid email address');
? AppLocalizations.of(context)!.enterEmailAddress
: (_isEmailValid
? AppLocalizations.of(context)!.emailLooksGood
: AppLocalizations.of(context)!.invalidEmailAddress);
return Container(
width: UIConstants.getResponsiveValue(
+16 -15
View File
@@ -7,6 +7,7 @@ import 'package:base_project/routes/route_names.dart';
import 'package:base_project/view_model/auth/auth_view_model.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../l10n/app_localizations.dart';
import '../../core/providers/dynamic_theme_provider.dart';
import '../../core/providers/theme_provider.dart';
@@ -497,7 +498,7 @@ class _LoginViewState extends State<LoginView> with TickerProviderStateMixin {
child: Column(
children: [
Text(
'Welcome Back!',
AppLocalizations.of(context)!.welcomeBack,
style: Theme.of(context).textTheme.headlineMedium?.copyWith(
color: colorScheme.primary,
fontWeight: FontWeight.w700,
@@ -507,7 +508,7 @@ class _LoginViewState extends State<LoginView> with TickerProviderStateMixin {
),
const SizedBox(height: UIConstants.spacing12),
Text(
'Sign in to continue to your account',
AppLocalizations.of(context)!.signInToContinue,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: colorScheme.onSurface.withOpacity(0.8),
fontWeight: FontWeight.w400,
@@ -557,8 +558,8 @@ class _LoginViewState extends State<LoginView> with TickerProviderStateMixin {
children: [
// Email Field
_buildEnhancedTextField(
label: 'Email Address',
hint: 'Enter your email',
label: AppLocalizations.of(context)!.emailAddress,
hint: AppLocalizations.of(context)!.enterYourEmail,
controller: _emailController,
focusNode: _emailFocusNode,
keyboardType: TextInputType.emailAddress,
@@ -569,11 +570,11 @@ class _LoginViewState extends State<LoginView> with TickerProviderStateMixin {
onSubmitted: (_) => _passwordFocusNode.requestFocus(),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Email is required';
return AppLocalizations.of(context)!.emailRequired;
}
if (!RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$')
.hasMatch(value)) {
return 'Please enter a valid email';
return AppLocalizations.of(context)!.validEmail;
}
return null;
},
@@ -583,8 +584,8 @@ class _LoginViewState extends State<LoginView> with TickerProviderStateMixin {
// Password Field
_buildEnhancedTextField(
label: 'Password',
hint: 'Enter your password',
label: AppLocalizations.of(context)!.password,
hint: AppLocalizations.of(context)!.enterYourPassword,
controller: _passwordController,
focusNode: _passwordFocusNode,
obscureText: !_isPasswordVisible,
@@ -607,10 +608,10 @@ class _LoginViewState extends State<LoginView> with TickerProviderStateMixin {
textInputAction: TextInputAction.done,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Password is required';
return AppLocalizations.of(context)!.passwordRequired;
}
if (value.length < 6) {
return 'Password must be at least 6 characters';
return AppLocalizations.of(context)!.passwordMinLength;
}
return null;
},
@@ -727,7 +728,7 @@ class _LoginViewState extends State<LoginView> with TickerProviderStateMixin {
),
const SizedBox(width: UIConstants.spacing6),
Text(
'Forgot Password?',
AppLocalizations.of(context)!.forgotPassword,
style: Theme.of(context).textTheme.labelSmall?.copyWith(
color: colorScheme.primary,
fontWeight: FontWeight.w600,
@@ -771,7 +772,7 @@ class _LoginViewState extends State<LoginView> with TickerProviderStateMixin {
child: Consumer<AuthViewModel>(
builder: (context, provider, child) {
return ModernButton(
text: 'Sign In',
text: AppLocalizations.of(context)!.signIn,
type: ModernButtonType.primary,
size: ModernButtonSize.large,
isLoading: provider.isLoading,
@@ -823,7 +824,7 @@ class _LoginViewState extends State<LoginView> with TickerProviderStateMixin {
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Don't have an account? ",
'${AppLocalizations.of(context)!.noAccount} ',
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Colors.grey.shade700,
fontWeight: FontWeight.w500,
@@ -834,7 +835,7 @@ class _LoginViewState extends State<LoginView> with TickerProviderStateMixin {
Navigator.pushNamed(context, RouteNames.getOtpView);
},
child: Text(
'Sign Up',
AppLocalizations.of(context)!.signUp,
style: Theme.of(context).textTheme.labelLarge?.copyWith(
color: colorScheme.primary,
fontWeight: FontWeight.w700,
@@ -870,7 +871,7 @@ class _LoginViewState extends State<LoginView> with TickerProviderStateMixin {
padding: const EdgeInsets.symmetric(
horizontal: UIConstants.spacing16),
child: Text(
'Or continue with',
AppLocalizations.of(context)!.orContinueWith,
style: Theme.of(context).textTheme.bodySmall?.copyWith(
color: Colors.white.withOpacity(0.9),
fontWeight: FontWeight.w500,
+2 -1
View File
@@ -1,5 +1,6 @@
import 'package:base_project/core/constants/ui_constants.dart';
import 'package:base_project/core/providers/dynamic_theme_provider.dart';
import 'package:base_project/l10n/app_localizations.dart';
import 'package:base_project/routes/route_names.dart';
import 'package:base_project/shared/widgets/app_bar/modern_app_bar.dart';
import 'package:base_project/shared/widgets/buttons/modern_button.dart';
@@ -322,7 +323,7 @@ class _SignUpViewState extends State<SignUpView> with TickerProviderStateMixin {
Consumer<AuthViewModel>(
builder: (context, provider, child) {
return ModernButton(
text: 'Sign Up',
text: AppLocalizations.of(context)!.signUp,
type: ModernButtonType.primary,
size: ModernButtonSize.large,
isLoading: provider.isLoading,
+2 -1
View File
@@ -1,3 +1,4 @@
import 'package:base_project/l10n/app_localizations.dart';
import 'package:flutter/material.dart';
class SignupView extends StatelessWidget {
@@ -14,7 +15,7 @@ class SignupView extends StatelessWidget {
},
icon: Icon(Icons.adaptive.arrow_back),
),
title: const Text("SignUp"),
title: Text(AppLocalizations.of(context)!.signUp),
),
);
}
+10 -8
View File
@@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
import 'package:pinput/pinput.dart';
import 'package:base_project/commans/widgets/custome_elevated_button.dart';
import 'package:provider/provider.dart';
import '../../l10n/app_localizations.dart';
import 'package:base_project/core/constants/ui_constants.dart';
import 'package:base_project/core/providers/dynamic_theme_provider.dart';
@@ -83,7 +84,7 @@ class _VerifyOtpViewState extends State<VerifyOtpView>
color: colorScheme.primary,
),
title: Text(
'Verify OTP',
AppLocalizations.of(context)!.verifyOtp,
style: Theme.of(context).textTheme.titleLarge?.copyWith(
color: colorScheme.primary,
fontWeight: FontWeight.w700,
@@ -147,7 +148,7 @@ class _VerifyOtpViewState extends State<VerifyOtpView>
),
const SizedBox(height: UIConstants.spacing16),
Text(
'Enter the 6-digit code sent to',
AppLocalizations.of(context)!.otpSentTo,
style: Theme.of(context)
.textTheme
.bodyMedium
@@ -157,7 +158,7 @@ class _VerifyOtpViewState extends State<VerifyOtpView>
textAlign: TextAlign.center,
),
Text(
widget.email ?? 'your email',
widget.email ?? AppLocalizations.of(context)!.yourEmail,
style:
Theme.of(context).textTheme.titleMedium?.copyWith(
color: colorScheme.primary,
@@ -233,7 +234,7 @@ class _VerifyOtpViewState extends State<VerifyOtpView>
onPressed: () async {
if (_otpController.text.length < 6) {
ToastMessageUtil.showToast(
message: 'Enter 6-digit OTP',
message: AppLocalizations.of(context)!.enterOtp,
toastType: ToastType.error,
);
return;
@@ -268,7 +269,7 @@ class _VerifyOtpViewState extends State<VerifyOtpView>
);
}
},
child: const Text('Verify OTP'),
child: Text(AppLocalizations.of(context)!.verifyOtp),
),
],
);
@@ -285,8 +286,9 @@ class _VerifyOtpViewState extends State<VerifyOtpView>
children: [
Text(
provider.isResendEnabled
? "Didn't receive code?"
: 'Resend in ${provider.start}s',
? AppLocalizations.of(context)!.didNotReceiveCode
: AppLocalizations.of(context)!
.resendIn(provider.start),
style: Theme.of(context)
.textTheme
.bodyMedium
@@ -304,7 +306,7 @@ class _VerifyOtpViewState extends State<VerifyOtpView>
}
: null,
child: Text(
'Resend',
AppLocalizations.of(context)!.resend,
style: TextStyle(
color: provider.isResendEnabled
? colorScheme.primary
+19 -17
View File
@@ -9,6 +9,7 @@ import 'package:base_project/utils/managers/user_manager.dart';
import 'package:provider/provider.dart';
import 'package:base_project/view_model/system_params/system_params_view_model.dart';
import 'package:flutter/material.dart';
import '../../l10n/app_localizations.dart';
class HomeView extends StatefulWidget {
const HomeView({super.key});
@@ -32,54 +33,54 @@ class _HomeViewState extends State<HomeView> with TickerProviderStateMixin {
// Dashboard stats (replace with real API data)
List<Map<String, dynamic>> _dashboardStats = [];
final List<Map<String, dynamic>> _quickActions = [
List<Map<String, dynamic>> _quickActions(BuildContext context) => [
{
'label': 'Profile',
'label': AppLocalizations.of(context)!.profile,
'icon': Icons.person,
'onTap': () {},
'backgroundColor': null, // Use theme default
},
{
'label': 'Settings',
'label': AppLocalizations.of(context)!.settings,
'icon': Icons.settings,
'onTap': () {},
'backgroundColor': null,
},
{
'label': 'Security',
'label': AppLocalizations.of(context)!.security,
'icon': Icons.security,
'onTap': () {},
'backgroundColor': null,
},
{
'label': 'Reports',
'label': AppLocalizations.of(context)!.reports,
'icon': Icons.analytics,
'onTap': () {},
'backgroundColor': null,
},
];
final List<DrawerItem> _drawerItems = [
List<DrawerItem> _drawerItems(BuildContext context) => [
DrawerItem(
icon: Icons.person,
title: 'Profile',
subtitle: 'Manage your account',
title: AppLocalizations.of(context)!.profile,
subtitle: AppLocalizations.of(context)!.manageAccount,
onTap: (context) {
Navigator.pushNamed(context, RouteNames.profileView);
},
),
DrawerItem(
icon: Icons.system_security_update,
title: 'System Parameters',
subtitle: 'Configure system settings',
title: AppLocalizations.of(context)!.systemParameters,
subtitle: AppLocalizations.of(context)!.configureSystemSettings,
onTap: (context) {
Navigator.pushNamed(context, RouteNames.systemParamsView);
},
),
DrawerItem(
icon: Icons.password,
title: 'Change Password',
subtitle: 'Update your password',
title: AppLocalizations.of(context)!.changePassword,
subtitle: AppLocalizations.of(context)!.updateYourPassword,
onTap: (context) {
Navigator.pushNamed(context, RouteNames.changePasswordView);
},
@@ -226,7 +227,7 @@ class _HomeViewState extends State<HomeView> with TickerProviderStateMixin {
return Scaffold(
backgroundColor: colorScheme.background,
appBar: ModernAppBar(
title: 'Dashboard',
title: AppLocalizations.of(context)!.dashboard,
centerTitle: false,
showLogoInTitle: true,
logoImage: _getDashboardLogoImage(colorScheme),
@@ -237,7 +238,7 @@ class _HomeViewState extends State<HomeView> with TickerProviderStateMixin {
Navigator.pushNamed(context, RouteNames.profileView);
},
),
drawer: ModernDrawer(items: _drawerItems),
drawer: ModernDrawer(items: _drawerItems(context)),
body: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
@@ -339,7 +340,8 @@ class _HomeViewState extends State<HomeView> with TickerProviderStateMixin {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Welcome back, ${userName ?? 'User'}! 👋',
AppLocalizations.of(context)!
.helloUser(userName ?? AppLocalizations.of(context)!.user),
style: theme.textTheme.headlineMedium?.copyWith(
color: colorScheme.onBackground,
fontWeight: FontWeight.w700,
@@ -468,9 +470,9 @@ class _HomeViewState extends State<HomeView> with TickerProviderStateMixin {
mainAxisSpacing: UIConstants.spacing16,
childAspectRatio: 1.0,
),
itemCount: _quickActions.length,
itemCount: _quickActions(context).length,
itemBuilder: (context, index) {
final action = _quickActions[index];
final action = _quickActions(context)[index];
return QuickActionButton(
label: action['label'],
icon: action['icon'],
@@ -1,5 +1,6 @@
import 'package:base_project/core/constants/ui_constants.dart';
import 'package:base_project/core/providers/dynamic_theme_provider.dart';
import 'package:base_project/l10n/app_localizations.dart';
import 'package:base_project/shared/widgets/app_bar/modern_app_bar.dart';
import 'package:base_project/shared/widgets/inputs/modern_text_field.dart';
import 'package:base_project/shared/widgets/buttons/modern_button.dart';
@@ -160,33 +161,37 @@ class _AccountUpdateViewState extends State<AccountUpdateView>
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
ModernTextField(
label: 'Company Name',
hint: 'Enter company name',
label: AppLocalizations.of(context)!.accCompanyName,
hint: AppLocalizations.of(context)!.accCompanyHint,
controller: _companyName,
prefixIcon: const Icon(Icons.business),
validator: (v) =>
(v == null || v.isEmpty) ? 'Required' : null,
(v == null || v.isEmpty)
? AppLocalizations.of(context)!.requiredVal
: null,
),
SizedBox(height: UIConstants.spacing20),
ModernTextField(
label: 'Workspace',
hint: 'Enter workspace',
label: AppLocalizations.of(context)!.accWorkspace,
hint: AppLocalizations.of(context)!.accWorkspaceHint,
controller: _workspace,
prefixIcon: const Icon(Icons.apartment_outlined),
validator: (v) =>
(v == null || v.isEmpty) ? 'Required' : null,
(v == null || v.isEmpty)
? AppLocalizations.of(context)!.requiredVal
: null,
),
SizedBox(height: UIConstants.spacing20),
ModernTextField(
label: 'GST Number',
hint: 'Enter GST number',
label: AppLocalizations.of(context)!.accGst,
hint: AppLocalizations.of(context)!.accGstHint,
controller: _gstNumber,
prefixIcon: const Icon(Icons.confirmation_number_outlined),
),
SizedBox(height: UIConstants.spacing20),
ModernTextField(
label: 'Mobile',
hint: 'Enter mobile number',
label: AppLocalizations.of(context)!.accMobile,
hint: AppLocalizations.of(context)!.accMobileHint,
controller: _mobile,
keyboardType: TextInputType.phone,
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
@@ -195,23 +200,23 @@ class _AccountUpdateViewState extends State<AccountUpdateView>
SizedBox(height: UIConstants.spacing20),
AbsorbPointer(
child: ModernTextField(
label: 'Email (read-only)',
hint: 'Email',
label: AppLocalizations.of(context)!.accEmailReadonly,
hint: AppLocalizations.of(context)!.email,
controller: _email,
prefixIcon: const Icon(Icons.email_outlined),
),
),
SizedBox(height: UIConstants.spacing20),
ModernTextField(
label: 'PAN Card',
hint: 'Enter PAN',
label: AppLocalizations.of(context)!.accPan,
hint: AppLocalizations.of(context)!.accPanHint,
controller: _pancard,
prefixIcon: const Icon(Icons.badge_outlined),
),
SizedBox(height: UIConstants.spacing20),
ModernTextField(
label: 'Working',
hint: 'Working status',
label: AppLocalizations.of(context)!.accWorking,
hint: AppLocalizations.of(context)!.accWorkingHint,
controller: _working,
prefixIcon: const Icon(Icons.work_outline),
),
@@ -223,7 +228,7 @@ class _AccountUpdateViewState extends State<AccountUpdateView>
onChanged: (v) => setState(() => _active = v),
),
const SizedBox(width: 8),
const Text('Active')
Text(AppLocalizations.of(context)!.nActive)
],
),
SizedBox(
@@ -234,7 +239,7 @@ class _AccountUpdateViewState extends State<AccountUpdateView>
desktop: UIConstants.spacing48,
)),
ModernButton(
text: 'Update Account',
text: AppLocalizations.of(context)!.accountUpdate,
type: ModernButtonType.primary,
size: ModernButtonSize.large,
isLoading: vm.isUpdating,
@@ -1,5 +1,6 @@
import 'package:base_project/commans/widgets/custom_textform_field.dart';
import 'package:base_project/commans/widgets/custome_elevated_button.dart';
import 'package:base_project/l10n/app_localizations.dart';
import 'package:base_project/resources/app_colors.dart';
import 'package:base_project/utils/managers/user_manager.dart';
import 'package:base_project/utils/validator/text_feild_validator.dart';
@@ -372,7 +373,7 @@ class _ChangePasswordState extends State<ChangePassword>
Consumer<ProfileViewModel>(
builder: (context, provider, _) {
return ModernButton(
text: 'Change Password',
text: AppLocalizations.of(context)!.changePassword,
type: ModernButtonType.primary,
size: ModernButtonSize.large,
isLoading: provider.isUpdating,
@@ -1,5 +1,6 @@
import 'package:base_project/commans/widgets/custom_textform_field.dart';
import 'package:base_project/commans/widgets/custome_elevated_button.dart';
import 'package:base_project/l10n/app_localizations.dart';
import 'package:base_project/model/user/user_profile.dart';
import 'package:base_project/resources/app_colors.dart';
import 'package:base_project/view_model/profile/profile_view_model.dart';
@@ -396,7 +397,7 @@ class _EditProfileState extends State<EditProfile>
Consumer<ProfileViewModel>(
builder: (context, provider, _) {
return ModernButton(
text: 'Save Changes',
text: AppLocalizations.of(context)!.saveChanges,
type: ModernButtonType.primary,
size: ModernButtonSize.large,
isLoading: provider.isUpdating,
@@ -6,6 +6,7 @@ import 'package:base_project/utils/managers/user_manager.dart';
import 'package:base_project/view/dashboard/profile/edit_profile.dart';
import 'package:base_project/view_model/profile/profile_view_model.dart';
import 'package:flutter/material.dart';
import '../../../l10n/app_localizations.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:provider/provider.dart';
import 'package:base_project/core/providers/dynamic_theme_provider.dart';
@@ -77,7 +78,7 @@ class _ProfileViewState extends State<ProfileView>
return Scaffold(
appBar: ModernAppBar(
title: 'Profile',
title: AppLocalizations.of(context)!.profile,
automaticallyImplyLeading: true,
leading: IconButton(
icon: Icon(Icons.arrow_back),
@@ -393,7 +394,7 @@ class _ProfileViewState extends State<ProfileView>
context,
colorScheme: colorScheme,
icon: Icons.edit_outlined,
title: 'Edit Profile',
title: AppLocalizations.of(context)!.editProfile,
subtitle: 'Update your personal information',
onTap: () {
Navigator.push(
@@ -411,7 +412,7 @@ class _ProfileViewState extends State<ProfileView>
context,
colorScheme: colorScheme,
icon: Icons.manage_accounts_outlined,
title: 'Account Update',
title: AppLocalizations.of(context)!.accountUpdate,
subtitle: 'Update company/workspace details',
onTap: () {
Navigator.push(
@@ -427,7 +428,7 @@ class _ProfileViewState extends State<ProfileView>
context,
colorScheme: colorScheme,
icon: Icons.lock_outline,
title: 'Change Password',
title: AppLocalizations.of(context)!.changePassword,
subtitle: 'Update your account security',
onTap: () {
Navigator.pushNamed(context, RouteNames.changePasswordView);
@@ -438,7 +439,7 @@ class _ProfileViewState extends State<ProfileView>
context,
colorScheme: colorScheme,
icon: Icons.logout,
title: 'Logout',
title: AppLocalizations.of(context)!.logout,
subtitle: 'Sign out of your account',
iconColor: colorScheme.error,
onTap: () => _showLogoutDialog(context, colorScheme),
@@ -541,10 +542,10 @@ class _ProfileViewState extends State<ProfileView>
size: UIConstants.iconSizeMedium,
),
const SizedBox(width: UIConstants.spacing12),
const Text("Confirm Logout"),
Text(AppLocalizations.of(context)!.confirmLogout),
],
),
content: const Text("Are you sure you want to log out?"),
content: Text(AppLocalizations.of(context)!.confirmLogoutBody),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
@@ -563,7 +564,7 @@ class _ProfileViewState extends State<ProfileView>
backgroundColor: colorScheme.error,
foregroundColor: colorScheme.onError,
),
child: const Text("Log Out"),
child: Text(AppLocalizations.of(context)!.logoutAction),
),
],
);
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import '../../l10n/app_localizations.dart';
class EditSystemParams extends StatelessWidget {
const EditSystemParams({super.key});
@@ -13,9 +14,9 @@ class EditSystemParams extends StatelessWidget {
},
icon: Icon(Icons.adaptive.arrow_back),
),
title: const Text("Edit System Parameters"),
title: Text(AppLocalizations.of(context)!.editSystemParameters),
),
);
}
}
}
@@ -10,6 +10,7 @@ import 'package:base_project/shared/widgets/theme_preview.dart';
import 'package:base_project/utils/managers/user_manager.dart';
import 'package:base_project/view_model/system_params/system_params_view_model.dart';
import 'package:flutter/material.dart';
import '../../l10n/app_localizations.dart';
import 'package:provider/provider.dart';
import 'package:base_project/core/providers/dynamic_theme_provider.dart';
@@ -235,7 +236,7 @@ class _SystemParametersViewState extends State<SystemParametersView>
return Scaffold(
backgroundColor: colorScheme.background,
appBar: ModernAppBar(
title: 'System Parameters',
title: AppLocalizations.of(context)!.systemParameters,
userAvatar: null,
userName: userName,
onProfilePressed: () {},
@@ -409,7 +410,7 @@ class _SystemParametersViewState extends State<SystemParametersView>
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'System Configuration',
AppLocalizations.of(context)!.sysConfigTitle,
style: theme.textTheme.headlineMedium?.copyWith(
color: colorScheme.onBackground,
fontWeight: FontWeight.w700,
@@ -417,7 +418,7 @@ class _SystemParametersViewState extends State<SystemParametersView>
),
const SizedBox(height: UIConstants.spacing8),
Text(
'Configure system-wide parameters and settings',
AppLocalizations.of(context)!.sysConfigSubtitle,
style: theme.textTheme.bodyLarge?.copyWith(
color: colorScheme.onSurfaceVariant,
),
@@ -691,7 +692,8 @@ class _SystemParametersViewState extends State<SystemParametersView>
),
const SizedBox(width: UIConstants.spacing8),
Text(
'Generating dynamic theme...',
AppLocalizations.of(context)!
.generatingTheme,
style: TextStyle(
color: Colors.blue,
fontSize: 12,
@@ -720,7 +722,8 @@ class _SystemParametersViewState extends State<SystemParametersView>
),
const SizedBox(width: UIConstants.spacing8),
Text(
'Dynamic theme applied! Colors extracted from logo.',
AppLocalizations.of(context)!
.themeApplied,
style: TextStyle(
color: Colors.green,
fontSize: 12,
@@ -742,7 +745,7 @@ class _SystemParametersViewState extends State<SystemParametersView>
SizedBox(
width: double.infinity,
child: ModernButton(
text: 'Upload Logo',
text: AppLocalizations.of(context)!.uploadLogo,
type: ModernButtonType.primary,
size: ModernButtonSize.medium,
icon: Icon(Icons.upload),
@@ -757,7 +760,7 @@ class _SystemParametersViewState extends State<SystemParametersView>
SizedBox(
width: double.infinity,
child: ModernButton(
text: 'Clear Logo',
text: AppLocalizations.of(context)!.clearLogo,
type: ModernButtonType.outline,
size: ModernButtonSize.medium,
icon: Icon(Icons.delete_outline),
@@ -788,7 +791,8 @@ class _SystemParametersViewState extends State<SystemParametersView>
const SizedBox(width: UIConstants.spacing8),
Expanded(
child: Text(
'Theme is applied immediately! Click "Upload Logo" to save the logo permanently to the database. The dynamic theme will work even if upload fails.',
AppLocalizations.of(context)!
.themeImmediateNote,
style: TextStyle(
color: AppColorScheme.info,
fontSize: 12,
@@ -806,7 +810,7 @@ class _SystemParametersViewState extends State<SystemParametersView>
SizedBox(
width: double.infinity,
child: ModernButton(
text: 'Upload New Logo',
text: AppLocalizations.of(context)!.uploadNewLogo,
type: ModernButtonType.primary,
size: ModernButtonSize.medium,
icon: Icon(Icons.upload),
@@ -821,7 +825,8 @@ class _SystemParametersViewState extends State<SystemParametersView>
SizedBox(
width: double.infinity,
child: ModernButton(
text: 'Remove Logo',
text:
AppLocalizations.of(context)!.removeLogo,
type: ModernButtonType.danger,
size: ModernButtonSize.medium,
icon: Icon(Icons.delete_outline),
@@ -852,7 +857,8 @@ class _SystemParametersViewState extends State<SystemParametersView>
const SizedBox(width: UIConstants.spacing8),
Expanded(
child: Text(
'Company logo is already uploaded and saved in the system. You can upload a new one or remove the existing logo.',
AppLocalizations.of(context)!
.logoAlreadyUploaded,
style: TextStyle(
color: AppColorScheme.success,
fontSize: 12,
@@ -913,7 +919,7 @@ class _SystemParametersViewState extends State<SystemParametersView>
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Enable Manual Override',
AppLocalizations.of(context)!.manualOverride,
style: theme.textTheme.titleMedium?.copyWith(
color: cs.onSurface,
fontWeight: FontWeight.w600,
@@ -938,7 +944,7 @@ class _SystemParametersViewState extends State<SystemParametersView>
),
const SizedBox(height: UIConstants.spacing12),
_buildColorRow(
label: 'Primary',
label: AppLocalizations.of(context)!.colorPrimary,
color: effectivePrimary,
onPick: () async {
final picked = await _pickColor(context, effectivePrimary);
@@ -949,7 +955,7 @@ class _SystemParametersViewState extends State<SystemParametersView>
),
const SizedBox(height: UIConstants.spacing12),
_buildColorRow(
label: 'Secondary',
label: AppLocalizations.of(context)!.colorSecondary,
color: effectiveSecondary,
onPick: () async {
final picked =
@@ -961,7 +967,7 @@ class _SystemParametersViewState extends State<SystemParametersView>
),
const SizedBox(height: UIConstants.spacing12),
_buildColorRow(
label: 'Tertiary',
label: AppLocalizations.of(context)!.colorTertiary,
color: effectiveTertiary,
onPick: () async {
final picked = await _pickColor(context, effectiveTertiary);
@@ -975,7 +981,8 @@ class _SystemParametersViewState extends State<SystemParametersView>
children: [
Expanded(
child: ModernButton(
text: 'Reset to Logo Colors',
text: AppLocalizations.of(context)!
.resetLogoColors,
type: ModernButtonType.outline,
size: ModernButtonSize.medium,
icon: Icon(Icons.refresh),
@@ -987,7 +994,8 @@ class _SystemParametersViewState extends State<SystemParametersView>
const SizedBox(width: UIConstants.spacing12),
Expanded(
child: ModernButton(
text: 'Reset to Default',
text: AppLocalizations.of(context)!
.resetDefault,
type: ModernButtonType.danger,
size: ModernButtonSize.medium,
icon: Icon(Icons.settings_backup_restore),
@@ -1041,7 +1049,7 @@ class _SystemParametersViewState extends State<SystemParametersView>
),
),
ModernButton(
text: 'Edit',
text: AppLocalizations.of(context)!.edit,
type: ModernButtonType.text,
size: ModernButtonSize.small,
onPressed: () async {
@@ -1073,7 +1081,7 @@ class _SystemParametersViewState extends State<SystemParametersView>
context: context,
builder: (context) {
return AlertDialog(
title: const Text('Pick a color'),
title: Text(AppLocalizations.of(context)!.pickColor),
content: SizedBox(
width: 320,
child: GridView.builder(
@@ -1105,7 +1113,7 @@ class _SystemParametersViewState extends State<SystemParametersView>
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('Cancel'),
child: Text(AppLocalizations.of(context)!.cancel),
),
],
);
@@ -1156,7 +1164,7 @@ class _SystemParametersViewState extends State<SystemParametersView>
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'User Registration',
AppLocalizations.of(context)!.userRegistration,
style: theme.textTheme.titleMedium?.copyWith(
color: colorScheme.onSurface,
fontWeight: FontWeight.w600,
@@ -1164,7 +1172,7 @@ class _SystemParametersViewState extends State<SystemParametersView>
),
const SizedBox(height: UIConstants.spacing4),
Text(
'Allow new users to register accounts',
AppLocalizations.of(context)!.allowUserRegistration,
style: theme.textTheme.bodySmall?.copyWith(
color: colorScheme.onSurfaceVariant,
),
@@ -1194,7 +1202,7 @@ class _SystemParametersViewState extends State<SystemParametersView>
return SizedBox(
width: double.infinity,
child: ModernButton(
text: 'Save Configuration',
text: AppLocalizations.of(context)!.saveConfiguration,
type: ModernButtonType.primary,
size: ModernButtonSize.large,
icon: Icon(Icons.save),
@@ -1266,16 +1274,18 @@ class _SystemParametersViewState extends State<SystemParametersView>
padding: EdgeInsets.zero,
children: [
_buildDrawerItem(
context, theme, colorScheme, Icons.home, 'Home', () {
context, theme, colorScheme, Icons.home,
AppLocalizations.of(context)!.drawerHome, () {
Navigator.of(context).pushReplacementNamed('/');
}),
_buildDrawerItem(context, theme, colorScheme, Icons.settings,
'System Parameters', () {
AppLocalizations.of(context)!.systemParameters, () {
Navigator.of(context)
.pushReplacementNamed('/system_parameters');
}, isSelected: true),
_buildDrawerItem(
context, theme, colorScheme, Icons.people, 'Users', () {
context, theme, colorScheme, Icons.people,
AppLocalizations.of(context)!.drawerUsers, () {
Navigator.of(context).pushReplacementNamed('/users');
}),
_buildDrawerItem(
@@ -1283,41 +1293,49 @@ class _SystemParametersViewState extends State<SystemParametersView>
Navigator.of(context).pushReplacementNamed('/roles');
}),
_buildDrawerItem(
context, theme, colorScheme, Icons.business, 'Departments',
context, theme, colorScheme, Icons.business,
AppLocalizations.of(context)!.drawerDepartments,
() {
Navigator.of(context).pushReplacementNamed('/departments');
}),
_buildDrawerItem(
context, theme, colorScheme, Icons.work, 'Positions', () {
context, theme, colorScheme, Icons.work,
AppLocalizations.of(context)!.drawerPositions, () {
Navigator.of(context).pushReplacementNamed('/positions');
}),
_buildDrawerItem(context, theme, colorScheme,
Icons.monetization_on, 'Charges', () {
Icons.monetization_on,
AppLocalizations.of(context)!.drawerCharges, () {
Navigator.of(context).pushReplacementNamed('/charges');
}),
_buildDrawerItem(
context, theme, colorScheme, Icons.calendar_today, 'Weeks',
context, theme, colorScheme, Icons.calendar_today,
AppLocalizations.of(context)!.drawerWeeks,
() {
Navigator.of(context).pushReplacementNamed('/weeks');
}),
_buildDrawerItem(
context, theme, colorScheme, Icons.schedule, 'Shifts', () {
context, theme, colorScheme, Icons.schedule,
AppLocalizations.of(context)!.drawerShifts, () {
Navigator.of(context).pushReplacementNamed('/shifts');
}),
_buildDrawerItem(
context, theme, colorScheme, Icons.payment, 'Billing', () {
context, theme, colorScheme, Icons.payment,
AppLocalizations.of(context)!.drawerBilling, () {
Navigator.of(context).pushReplacementNamed('/billing');
}),
_buildDrawerItem(context, theme, colorScheme, Icons.swap_horiz,
'EDI Settings', () {
AppLocalizations.of(context)!.drawerEdi, () {
Navigator.of(context).pushReplacementNamed('/edi_settings');
}),
_buildDrawerItem(context, theme, colorScheme,
Icons.business_center, 'Company', () {
Icons.business_center,
AppLocalizations.of(context)!.drawerCompany, () {
Navigator.of(context).pushReplacementNamed('/company');
}),
_buildDrawerItem(
context, theme, colorScheme, Icons.image, 'Logo', () {
context, theme, colorScheme, Icons.image,
AppLocalizations.of(context)!.drawerLogo, () {
Navigator.of(context).pushReplacementNamed('/logo');
}),
],
@@ -1328,7 +1346,7 @@ class _SystemParametersViewState extends State<SystemParametersView>
Container(
padding: const EdgeInsets.all(UIConstants.spacing24),
child: ModernButton(
text: 'Logout',
text: AppLocalizations.of(context)!.logoutAction,
type: ModernButtonType.danger,
size: ModernButtonSize.medium,
icon: Icon(Icons.logout),
@@ -1,3 +1,4 @@
import 'package:base_project/l10n/app_localizations.dart';
import 'package:base_project/utils/image_constant.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
@@ -27,16 +28,16 @@ class ShowSnackAlert {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (color1 == Colors.red.shade400)
const Text(
'Oh Snap!',
Text(
AppLocalizations.of(context)!.ohSnap,
style: TextStyle(fontSize: 18, color: Colors.white),
),
if (color1 == Colors.orange.shade400)
const Text('Alert',
Text(AppLocalizations.of(context)!.alertTitle,
style:
TextStyle(fontSize: 18, color: Colors.white)),
if (color1 == Colors.green.shade600)
const Text('Success',
Text(AppLocalizations.of(context)!.successTitle,
style:
TextStyle(fontSize: 18, color: Colors.white)),
Text(
+16 -11
View File
@@ -446,6 +446,11 @@ packages:
url: "https://pub.dev"
source: hosted
version: "5.0.0"
flutter_localizations:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
@@ -692,10 +697,10 @@ packages:
dependency: "direct main"
description:
name: intl
sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5"
sha256: "1ca20c894b1717686a2319b8548763d812bc0aabdac580420a44c5178c57a867"
url: "https://pub.dev"
source: hosted
version: "0.20.2"
version: "0.20.3"
intl_phone_number_input:
dependency: "direct main"
description:
@@ -844,10 +849,10 @@ packages:
dependency: transitive
description:
name: matcher
sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6"
sha256: "31bd099b47c10cd1aeb55146a2d46ce0277630ecef3f7dae54ad7873f36696cd"
url: "https://pub.dev"
source: hosted
version: "0.12.18"
version: "0.12.20"
material_color_utilities:
dependency: transitive
description:
@@ -860,10 +865,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
sha256: "307249ce4ff29d58a18e97f6345f539382eb9c9c29ecda628900f31de0443dd9"
url: "https://pub.dev"
source: hosted
version: "1.17.0"
version: "1.19.0"
mime:
dependency: transitive
description:
@@ -1353,10 +1358,10 @@ packages:
dependency: transitive
description:
name: test_api
sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636"
sha256: "2a122cbe059f8b610d3a5415f42e255b6c17b1f21eee1d960f31080237fb4f11"
url: "https://pub.dev"
source: hosted
version: "0.7.9"
version: "0.7.12"
typed_data:
dependency: transitive
description:
@@ -1473,10 +1478,10 @@ packages:
dependency: transitive
description:
name: vector_math
sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
sha256: "92b9910f66ed1057fd4da7b040ae7c74cafacf885bdc81be496928d5049b032d"
url: "https://pub.dev"
source: hosted
version: "2.2.0"
version: "2.4.3"
video_player:
dependency: "direct main"
description:
@@ -1590,5 +1595,5 @@ packages:
source: hosted
version: "3.1.3"
sdks:
dart: ">=3.9.0 <4.0.0"
dart: ">=3.11.0-0 <4.0.0"
flutter: ">=3.35.0"
+4
View File
@@ -30,6 +30,8 @@ environment:
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
another_flushbar: ^1.12.30
cupertino_icons: ^1.0.8
path_provider: ^2.1.5
@@ -100,6 +102,7 @@ dev_dependencies:
# The following section is specific to Flutter packages.
flutter:
generate: true
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
@@ -110,6 +113,7 @@ flutter:
- assets/
- assets/images/
- assets/icon/
- assets/translations_dynamic/
# assets:
# - images/a_dot_burr.jpeg
+20
View File
@@ -0,0 +1,20 @@
import 'package:base_project/l10n/app_localizations.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
test('English and Hindi catalogs expose the same essential messages', () {
final english = AppLocalizations(const Locale('en'));
final hindi = AppLocalizations(const Locale('hi'));
expect(english.searchEntity('student'), 'Search student...');
expect(hindi.searchEntity('छात्र'), 'छात्र खोजें...');
expect(english.entityRequired('Email'), 'Email is required');
expect(hindi.entityRequired('ईमेल'), 'ईमेल आवश्यक है');
});
test('only configured locales are supported', () {
expect(AppLocalizations.supportedLocales, contains(const Locale('en')));
expect(AppLocalizations.supportedLocales, contains(const Locale('hi')));
});
}
-30
View File
@@ -1,30 +0,0 @@
// This is a basic Flutter widget test.
//
// To perform an interaction with a widget in your test, use the WidgetTester
// utility in the flutter_test package. For example, you can send tap and scroll
// gestures. You can also use WidgetTester to find child widgets in the widget
// tree, read text, and verify that the values of widget properties are correct.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:base_project/main.dart';
void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(const MyApp());
// Verify that our counter starts at 0.
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);
// Tap the '+' icon and trigger a frame.
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
// Verify that our counter has incremented.
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
});
}