added i8n
This commit is contained in:
parent
1c861e1f4b
commit
fa0e43885a
|
|
@ -0,0 +1,6 @@
|
||||||
|
arb-dir: lib/l10n
|
||||||
|
template-arb-file: app_en.arb
|
||||||
|
output-localization-file: app_localizations.dart
|
||||||
|
output-class: AppLocalizations
|
||||||
|
synthetic-package: false
|
||||||
|
output-dir: lib/l10n
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
import '../../l10n/app_localizations.dart';
|
||||||
|
|
||||||
|
/// Persists UI language (English / Telugu) for [AppLocalizations].
|
||||||
|
class LocaleController extends GetxController {
|
||||||
|
static LocaleController get to => Get.find();
|
||||||
|
|
||||||
|
static const String _prefKey = 'app_locale';
|
||||||
|
|
||||||
|
final Rx<Locale> locale = const Locale('en').obs;
|
||||||
|
|
||||||
|
/// Call from [main] after [WidgetsFlutterBinding.ensureInitialized].
|
||||||
|
Future<void> ensureLoaded() async {
|
||||||
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
final code = prefs.getString(_prefKey);
|
||||||
|
if (code == 'te' || code == 'en') {
|
||||||
|
locale.value = Locale(code!);
|
||||||
|
} else {
|
||||||
|
locale.value = const Locale('en');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> setLocale(Locale value) async {
|
||||||
|
if (value.languageCode != 'en' && value.languageCode != 'te') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
locale.value = value;
|
||||||
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
await prefs.setString(_prefKey, value.languageCode);
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Current choice label for settings subtitle (uses [l10n] for both languages).
|
||||||
|
String currentLanguageLabel(AppLocalizations l10n) {
|
||||||
|
switch (locale.value.languageCode) {
|
||||||
|
case 'te':
|
||||||
|
return l10n.languageTelugu;
|
||||||
|
case 'en':
|
||||||
|
default:
|
||||||
|
return l10n.languageEnglish;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import '../../../l10n/l10n_x.dart';
|
||||||
import '../../../shared/widgets/empty_state_widget.dart';
|
import '../../../shared/widgets/empty_state_widget.dart';
|
||||||
|
|
||||||
class StateView extends StatelessWidget {
|
class StateView extends StatelessWidget {
|
||||||
|
|
@ -8,8 +9,8 @@ class StateView extends StatelessWidget {
|
||||||
final bool isEmpty;
|
final bool isEmpty;
|
||||||
final Widget child;
|
final Widget child;
|
||||||
final Widget? loading;
|
final Widget? loading;
|
||||||
final String emptyTitle;
|
final String? emptyTitle;
|
||||||
final String emptyMessage;
|
final String? emptyMessage;
|
||||||
final EmptyStateType emptyType;
|
final EmptyStateType emptyType;
|
||||||
|
|
||||||
const StateView({
|
const StateView({
|
||||||
|
|
@ -20,8 +21,8 @@ class StateView extends StatelessWidget {
|
||||||
this.onRetry,
|
this.onRetry,
|
||||||
this.isEmpty = false,
|
this.isEmpty = false,
|
||||||
this.loading,
|
this.loading,
|
||||||
this.emptyTitle = 'Nothing here yet',
|
this.emptyTitle,
|
||||||
this.emptyMessage = 'Try again later.',
|
this.emptyMessage,
|
||||||
this.emptyType = EmptyStateType.noResults,
|
this.emptyType = EmptyStateType.noResults,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -35,6 +36,7 @@ class StateView extends StatelessWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
|
final l = context.l10n;
|
||||||
return Center(
|
return Center(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(24),
|
padding: const EdgeInsets.all(24),
|
||||||
|
|
@ -44,7 +46,7 @@ class StateView extends StatelessWidget {
|
||||||
Icon(Icons.error_outline, size: 44, color: Theme.of(context).colorScheme.error),
|
Icon(Icons.error_outline, size: 44, color: Theme.of(context).colorScheme.error),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
Text(
|
Text(
|
||||||
'Something went wrong',
|
l.stateSomethingWentWrong,
|
||||||
style: Theme.of(context).textTheme.titleMedium,
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
|
|
@ -60,7 +62,7 @@ class StateView extends StatelessWidget {
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
FilledButton(
|
FilledButton(
|
||||||
onPressed: onRetry,
|
onPressed: onRetry,
|
||||||
child: const Text('Retry'),
|
child: Text(l.retry),
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
|
@ -70,12 +72,13 @@ class StateView extends StatelessWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isEmpty) {
|
if (isEmpty) {
|
||||||
|
final l = context.l10n;
|
||||||
return Center(
|
return Center(
|
||||||
child: EmptyStateWidget(
|
child: EmptyStateWidget(
|
||||||
type: emptyType,
|
type: emptyType,
|
||||||
customTitle: emptyTitle,
|
customTitle: emptyTitle,
|
||||||
customMessage: emptyMessage,
|
customMessage: emptyMessage,
|
||||||
actionLabel: onRetry != null ? 'Retry' : null,
|
actionLabel: onRetry != null ? l.retry : null,
|
||||||
onActionPressed: onRetry,
|
onActionPressed: onRetry,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import 'package:get/get.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import '../models/user.dart';
|
import '../models/user.dart';
|
||||||
import 'api_service.dart';
|
import 'api_service.dart';
|
||||||
|
import '../../l10n/l10n_x.dart';
|
||||||
|
|
||||||
class AuthService extends GetxController {
|
class AuthService extends GetxController {
|
||||||
static AuthService get to => Get.find();
|
static AuthService get to => Get.find();
|
||||||
|
|
@ -87,12 +88,12 @@ class AuthService extends GetxController {
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
Get.snackbar('Signup Failed', response['message']);
|
Get.snackbar(L10nSvc.of().signupFailedTitle, response['message']);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Signup error: $e');
|
print('Signup error: $e');
|
||||||
Get.snackbar('Error', 'Signup failed. Please try again.');
|
Get.snackbar(L10nSvc.of().snackTitleError, L10nSvc.of().signupFailedGeneric);
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
_isLoading.value = false;
|
_isLoading.value = false;
|
||||||
|
|
@ -118,12 +119,12 @@ class AuthService extends GetxController {
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
Get.snackbar('Login Failed', response['message']);
|
Get.snackbar(L10nSvc.of().loginFailedTitle, response['message']);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Login error: $e');
|
print('Login error: $e');
|
||||||
Get.snackbar('Error', 'Login failed. Please try again.');
|
Get.snackbar(L10nSvc.of().snackTitleError, L10nSvc.of().loginFailedGeneric);
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
_isLoading.value = false;
|
_isLoading.value = false;
|
||||||
|
|
@ -159,15 +160,15 @@ class AuthService extends GetxController {
|
||||||
final response = await _apiService.changePassword(currentPassword, newPassword);
|
final response = await _apiService.changePassword(currentPassword, newPassword);
|
||||||
|
|
||||||
if (response['success']) {
|
if (response['success']) {
|
||||||
Get.snackbar('Success', 'Password changed successfully');
|
Get.snackbar(L10nSvc.of().snackTitleSuccess, L10nSvc.of().passwordChangedSuccess);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
Get.snackbar('Failed', response['message']);
|
Get.snackbar(L10nSvc.of().snackTitleError, response['message']);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Change password error: $e');
|
print('Change password error: $e');
|
||||||
Get.snackbar('Error', 'Failed to change password');
|
Get.snackbar(L10nSvc.of().snackTitleError, L10nSvc.of().failedChangePassword);
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
_isLoading.value = false;
|
_isLoading.value = false;
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import '../models/monthly_draw.dart';
|
||||||
import '../models/financial_table_entry.dart';
|
import '../models/financial_table_entry.dart';
|
||||||
import '../models/user.dart';
|
import '../models/user.dart';
|
||||||
import 'api_service.dart';
|
import 'api_service.dart';
|
||||||
|
import '../../l10n/l10n_x.dart';
|
||||||
|
|
||||||
class ChitGroupService extends GetxController {
|
class ChitGroupService extends GetxController {
|
||||||
static ChitGroupService get to => Get.find();
|
static ChitGroupService get to => Get.find();
|
||||||
|
|
@ -55,11 +56,11 @@ class ChitGroupService extends GetxController {
|
||||||
print('Successfully loaded ${_chitGroups.length} chit groups');
|
print('Successfully loaded ${_chitGroups.length} chit groups');
|
||||||
} else {
|
} else {
|
||||||
print('API returned error: ${response['message']}');
|
print('API returned error: ${response['message']}');
|
||||||
Get.snackbar('Error', response['message']);
|
Get.snackbar(L10nSvc.of().snackTitleError, response['message']);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error loading manager chit groups: $e');
|
print('Error loading manager chit groups: $e');
|
||||||
Get.snackbar('Error', 'Failed to load chit groups');
|
Get.snackbar(L10nSvc.of().snackTitleError, L10nSvc.of().failedLoadChitGroups);
|
||||||
} finally {
|
} finally {
|
||||||
_isLoading.value = false;
|
_isLoading.value = false;
|
||||||
}
|
}
|
||||||
|
|
@ -76,11 +77,11 @@ class ChitGroupService extends GetxController {
|
||||||
final groupsData = response['data']['chitGroups'] as List;
|
final groupsData = response['data']['chitGroups'] as List;
|
||||||
_chitGroups.value = groupsData.map((json) => ChitGroup.fromJson(json)).toList();
|
_chitGroups.value = groupsData.map((json) => ChitGroup.fromJson(json)).toList();
|
||||||
} else {
|
} else {
|
||||||
Get.snackbar('Error', response['message']);
|
Get.snackbar(L10nSvc.of().snackTitleError, response['message']);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error loading member chit groups: $e');
|
print('Error loading member chit groups: $e');
|
||||||
Get.snackbar('Error', 'Failed to load chit groups');
|
Get.snackbar(L10nSvc.of().snackTitleError, L10nSvc.of().failedLoadChitGroups);
|
||||||
} finally {
|
} finally {
|
||||||
_isLoading.value = false;
|
_isLoading.value = false;
|
||||||
}
|
}
|
||||||
|
|
@ -96,15 +97,15 @@ class ChitGroupService extends GetxController {
|
||||||
if (response['success']) {
|
if (response['success']) {
|
||||||
final newGroup = ChitGroup.fromJson(response['data']);
|
final newGroup = ChitGroup.fromJson(response['data']);
|
||||||
_chitGroups.add(newGroup);
|
_chitGroups.add(newGroup);
|
||||||
Get.snackbar('Success', 'Chitfund created successfully');
|
Get.snackbar(L10nSvc.of().snackTitleSuccess, L10nSvc.of().chitfundCreatedSuccess);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
Get.snackbar('Error', response['message']);
|
Get.snackbar(L10nSvc.of().snackTitleError, response['message']);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error creating chit group: $e');
|
print('Error creating chit group: $e');
|
||||||
Get.snackbar('Error', 'Failed to create chit group');
|
Get.snackbar(L10nSvc.of().snackTitleError, L10nSvc.of().failedCreateChitGroup);
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
_isLoading.value = false;
|
_isLoading.value = false;
|
||||||
|
|
@ -122,12 +123,12 @@ class ChitGroupService extends GetxController {
|
||||||
await loadChitGroupDetails(groupId);
|
await loadChitGroupDetails(groupId);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
Get.snackbar('Error', response['message']);
|
Get.snackbar(L10nSvc.of().snackTitleError, response['message']);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error updating chit group: $e');
|
print('Error updating chit group: $e');
|
||||||
Get.snackbar('Error', 'Failed to update chit group');
|
Get.snackbar(L10nSvc.of().snackTitleError, L10nSvc.of().failedUpdateChitGroup);
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
_isLoading.value = false;
|
_isLoading.value = false;
|
||||||
|
|
@ -143,15 +144,15 @@ class ChitGroupService extends GetxController {
|
||||||
|
|
||||||
if (response['success']) {
|
if (response['success']) {
|
||||||
_chitGroups.removeWhere((g) => g.id == groupId);
|
_chitGroups.removeWhere((g) => g.id == groupId);
|
||||||
Get.snackbar('Success', 'Chit group deleted successfully');
|
Get.snackbar(L10nSvc.of().snackTitleSuccess, L10nSvc.of().chitGroupDeletedSuccess);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
Get.snackbar('Error', response['message']);
|
Get.snackbar(L10nSvc.of().snackTitleError, response['message']);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error deleting chit group: $e');
|
print('Error deleting chit group: $e');
|
||||||
Get.snackbar('Error', 'Failed to delete chit group');
|
Get.snackbar(L10nSvc.of().snackTitleError, L10nSvc.of().failedDeleteChitGroup);
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
_isLoading.value = false;
|
_isLoading.value = false;
|
||||||
|
|
@ -169,11 +170,11 @@ class ChitGroupService extends GetxController {
|
||||||
final group = ChitGroup.fromJson(response['data']);
|
final group = ChitGroup.fromJson(response['data']);
|
||||||
_selectedGroup.value = group;
|
_selectedGroup.value = group;
|
||||||
} else {
|
} else {
|
||||||
Get.snackbar('Error', response['message']);
|
Get.snackbar(L10nSvc.of().snackTitleError, response['message']);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error loading chit group details: $e');
|
print('Error loading chit group details: $e');
|
||||||
Get.snackbar('Error', 'Failed to load group details');
|
Get.snackbar(L10nSvc.of().snackTitleError, L10nSvc.of().failedLoadGroupDetails);
|
||||||
} finally {
|
} finally {
|
||||||
_isLoading.value = false;
|
_isLoading.value = false;
|
||||||
}
|
}
|
||||||
|
|
@ -193,7 +194,7 @@ class ChitGroupService extends GetxController {
|
||||||
if (showErrors) {
|
if (showErrors) {
|
||||||
// Use post frame callback to avoid showing snackbar during build
|
// Use post frame callback to avoid showing snackbar during build
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
Get.snackbar('Error', response['message']);
|
Get.snackbar(L10nSvc.of().snackTitleError, response['message']);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -202,7 +203,7 @@ class ChitGroupService extends GetxController {
|
||||||
if (showErrors) {
|
if (showErrors) {
|
||||||
// Use post frame callback to avoid showing snackbar during build
|
// Use post frame callback to avoid showing snackbar during build
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
Get.snackbar('Error', 'Failed to load group members');
|
Get.snackbar(L10nSvc.of().snackTitleError, L10nSvc.of().failedLoadGroupMembers);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
|
@ -220,15 +221,15 @@ class ChitGroupService extends GetxController {
|
||||||
if (response['success']) {
|
if (response['success']) {
|
||||||
// Reload group members
|
// Reload group members
|
||||||
await loadGroupMembers(groupId);
|
await loadGroupMembers(groupId);
|
||||||
Get.snackbar('Success', 'Member added successfully');
|
Get.snackbar(L10nSvc.of().snackTitleSuccess, L10nSvc.of().memberAddedSuccess);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
Get.snackbar('Error', response['message']);
|
Get.snackbar(L10nSvc.of().snackTitleError, response['message']);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error adding member: $e');
|
print('Error adding member: $e');
|
||||||
Get.snackbar('Error', 'Failed to add member');
|
Get.snackbar(L10nSvc.of().snackTitleError, L10nSvc.of().failedAddMember);
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
_isLoading.value = false;
|
_isLoading.value = false;
|
||||||
|
|
@ -245,15 +246,15 @@ class ChitGroupService extends GetxController {
|
||||||
if (response['success']) {
|
if (response['success']) {
|
||||||
// Reload group members
|
// Reload group members
|
||||||
await loadGroupMembers(groupId);
|
await loadGroupMembers(groupId);
|
||||||
Get.snackbar('Success', 'Member removed successfully');
|
Get.snackbar(L10nSvc.of().snackTitleSuccess, L10nSvc.of().memberRemovedSuccess);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
Get.snackbar('Error', response['message']);
|
Get.snackbar(L10nSvc.of().snackTitleError, response['message']);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error removing member: $e');
|
print('Error removing member: $e');
|
||||||
Get.snackbar('Error', 'Failed to remove member');
|
Get.snackbar(L10nSvc.of().snackTitleError, L10nSvc.of().failedRemoveMember);
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
_isLoading.value = false;
|
_isLoading.value = false;
|
||||||
|
|
@ -313,15 +314,15 @@ class ChitGroupService extends GetxController {
|
||||||
if (response['success']) {
|
if (response['success']) {
|
||||||
// Reload group members
|
// Reload group members
|
||||||
await loadGroupMembers(groupId);
|
await loadGroupMembers(groupId);
|
||||||
Get.snackbar('Success', 'Member status updated successfully');
|
Get.snackbar(L10nSvc.of().snackTitleSuccess, L10nSvc.of().memberStatusUpdatedSuccess);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
Get.snackbar('Error', response['message']);
|
Get.snackbar(L10nSvc.of().snackTitleError, response['message']);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error updating member status: $e');
|
print('Error updating member status: $e');
|
||||||
Get.snackbar('Error', 'Failed to update member status');
|
Get.snackbar(L10nSvc.of().snackTitleError, L10nSvc.of().failedUpdateMemberStatus);
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
_isLoading.value = false;
|
_isLoading.value = false;
|
||||||
|
|
@ -339,11 +340,11 @@ class ChitGroupService extends GetxController {
|
||||||
final paymentsData = response['data']['payments'] as List;
|
final paymentsData = response['data']['payments'] as List;
|
||||||
_groupPayments.value = paymentsData.map((json) => Payment.fromJson(json)).toList();
|
_groupPayments.value = paymentsData.map((json) => Payment.fromJson(json)).toList();
|
||||||
} else {
|
} else {
|
||||||
Get.snackbar('Error', response['message']);
|
Get.snackbar(L10nSvc.of().snackTitleError, response['message']);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error loading group payments: $e');
|
print('Error loading group payments: $e');
|
||||||
Get.snackbar('Error', 'Failed to load payments');
|
Get.snackbar(L10nSvc.of().snackTitleError, L10nSvc.of().failedLoadPayments);
|
||||||
} finally {
|
} finally {
|
||||||
_isLoading.value = false;
|
_isLoading.value = false;
|
||||||
}
|
}
|
||||||
|
|
@ -359,15 +360,15 @@ class ChitGroupService extends GetxController {
|
||||||
if (response['success']) {
|
if (response['success']) {
|
||||||
// Reload group payments
|
// Reload group payments
|
||||||
await loadGroupPayments(data['group_id']);
|
await loadGroupPayments(data['group_id']);
|
||||||
Get.snackbar('Success', 'Payment recorded successfully');
|
Get.snackbar(L10nSvc.of().snackTitleSuccess, L10nSvc.of().paymentRecordedSuccess);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
Get.snackbar('Error', response['message']);
|
Get.snackbar(L10nSvc.of().snackTitleError, response['message']);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error recording payment: $e');
|
print('Error recording payment: $e');
|
||||||
Get.snackbar('Error', 'Failed to record payment');
|
Get.snackbar(L10nSvc.of().snackTitleError, L10nSvc.of().failedRecordPayment);
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
_isLoading.value = false;
|
_isLoading.value = false;
|
||||||
|
|
@ -384,11 +385,11 @@ class ChitGroupService extends GetxController {
|
||||||
if (response['success']) {
|
if (response['success']) {
|
||||||
_groupStats.value = response['data'];
|
_groupStats.value = response['data'];
|
||||||
} else {
|
} else {
|
||||||
Get.snackbar('Error', response['message']);
|
Get.snackbar(L10nSvc.of().snackTitleError, response['message']);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error loading group stats: $e');
|
print('Error loading group stats: $e');
|
||||||
Get.snackbar('Error', 'Failed to load group statistics');
|
Get.snackbar(L10nSvc.of().snackTitleError, L10nSvc.of().failedLoadGroupStatistics);
|
||||||
} finally {
|
} finally {
|
||||||
_isLoading.value = false;
|
_isLoading.value = false;
|
||||||
}
|
}
|
||||||
|
|
@ -408,15 +409,15 @@ class ChitGroupService extends GetxController {
|
||||||
final updatedGroup = ChitGroup.fromJson(response['data']);
|
final updatedGroup = ChitGroup.fromJson(response['data']);
|
||||||
_chitGroups[index] = updatedGroup;
|
_chitGroups[index] = updatedGroup;
|
||||||
}
|
}
|
||||||
Get.snackbar('Success', 'Chitfund started successfully');
|
Get.snackbar(L10nSvc.of().snackTitleSuccess, L10nSvc.of().chitfundStartedSuccess);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
Get.snackbar('Error', response['message']);
|
Get.snackbar(L10nSvc.of().snackTitleError, response['message']);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error starting chit group: $e');
|
print('Error starting chit group: $e');
|
||||||
Get.snackbar('Error', 'Failed to start chit group');
|
Get.snackbar(L10nSvc.of().snackTitleError, L10nSvc.of().failedStartChitGroup);
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
_isLoading.value = false;
|
_isLoading.value = false;
|
||||||
|
|
@ -450,11 +451,11 @@ class ChitGroupService extends GetxController {
|
||||||
))
|
))
|
||||||
.toList();
|
.toList();
|
||||||
} else {
|
} else {
|
||||||
Get.snackbar('Error', response['message']);
|
Get.snackbar(L10nSvc.of().snackTitleError, response['message']);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error loading group monthly draws: $e');
|
print('Error loading group monthly draws: $e');
|
||||||
Get.snackbar('Error', 'Failed to load monthly draws');
|
Get.snackbar(L10nSvc.of().snackTitleError, L10nSvc.of().failedLoadMonthlyDraws);
|
||||||
} finally {
|
} finally {
|
||||||
_isLoading.value = false;
|
_isLoading.value = false;
|
||||||
}
|
}
|
||||||
|
|
@ -499,14 +500,14 @@ class ChitGroupService extends GetxController {
|
||||||
return {};
|
return {};
|
||||||
} else {
|
} else {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
Get.snackbar('Error', response['message']?.toString() ?? 'Failed');
|
Get.snackbar(L10nSvc.of().snackTitleError, response['message']?.toString() ?? L10nSvc.of().operationFailedShort);
|
||||||
});
|
});
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error creating monthly draw: $e');
|
print('Error creating monthly draw: $e');
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
Get.snackbar('Error', 'Failed to create monthly draw');
|
Get.snackbar(L10nSvc.of().snackTitleError, L10nSvc.of().failedCreateMonthlyDraw);
|
||||||
});
|
});
|
||||||
return null;
|
return null;
|
||||||
} finally {
|
} finally {
|
||||||
|
|
@ -524,11 +525,11 @@ class ChitGroupService extends GetxController {
|
||||||
if (response['success']) {
|
if (response['success']) {
|
||||||
_drawStats.value = response['data'];
|
_drawStats.value = response['data'];
|
||||||
} else {
|
} else {
|
||||||
Get.snackbar('Error', response['message']);
|
Get.snackbar(L10nSvc.of().snackTitleError, response['message']);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error loading draw statistics: $e');
|
print('Error loading draw statistics: $e');
|
||||||
Get.snackbar('Error', 'Failed to load draw statistics');
|
Get.snackbar(L10nSvc.of().snackTitleError, L10nSvc.of().failedLoadDrawStatistics);
|
||||||
} finally {
|
} finally {
|
||||||
_isLoading.value = false;
|
_isLoading.value = false;
|
||||||
}
|
}
|
||||||
|
|
@ -555,12 +556,12 @@ class ChitGroupService extends GetxController {
|
||||||
_financialData.value = entries;
|
_financialData.value = entries;
|
||||||
} else {
|
} else {
|
||||||
print('API returned error: ${response['message']}');
|
print('API returned error: ${response['message']}');
|
||||||
Get.snackbar('Error', response['message']);
|
Get.snackbar(L10nSvc.of().snackTitleError, response['message']);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error loading group financial data: $e');
|
print('Error loading group financial data: $e');
|
||||||
print('Error stack trace: ${e.toString()}');
|
print('Error stack trace: ${e.toString()}');
|
||||||
Get.snackbar('Error', 'Failed to load financial data');
|
Get.snackbar(L10nSvc.of().snackTitleError, L10nSvc.of().failedLoadFinancialData);
|
||||||
} finally {
|
} finally {
|
||||||
_isLoading.value = false;
|
_isLoading.value = false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import '../../../core/design_system/app_components/auth_shell.dart';
|
||||||
import '../../../core/design_system/app_components/app_card.dart';
|
import '../../../core/design_system/app_components/app_card.dart';
|
||||||
import '../../../core/design_system/app_spacing.dart';
|
import '../../../core/design_system/app_spacing.dart';
|
||||||
import '../../../core/design_system/app_text.dart';
|
import '../../../core/design_system/app_text.dart';
|
||||||
|
import '../../../l10n/l10n_x.dart';
|
||||||
import 'signup_screen.dart';
|
import 'signup_screen.dart';
|
||||||
|
|
||||||
class LoginScreen extends StatefulWidget {
|
class LoginScreen extends StatefulWidget {
|
||||||
|
|
@ -37,10 +38,11 @@ class _LoginScreenState extends State<LoginScreen> {
|
||||||
_passwordController.text,
|
_passwordController.text,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!success) {
|
if (!success && mounted) {
|
||||||
|
final l = context.l10n;
|
||||||
SnackbarUtil.showError(
|
SnackbarUtil.showError(
|
||||||
'Invalid mobile number or password. Please try again.',
|
l.loginInvalidCredentials,
|
||||||
title: 'Login Failed',
|
title: l.loginFailedTitle,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -48,6 +50,7 @@ class _LoginScreenState extends State<LoginScreen> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final l = context.l10n;
|
||||||
final scheme = Theme.of(context).colorScheme;
|
final scheme = Theme.of(context).colorScheme;
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: AuthShell(
|
body: AuthShell(
|
||||||
|
|
@ -61,7 +64,7 @@ class _LoginScreenState extends State<LoginScreen> {
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Semantics(
|
Semantics(
|
||||||
label: 'LuckyChit logo',
|
label: '${l.appDisplayName} logo',
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.account_balance_wallet_rounded,
|
Icons.account_balance_wallet_rounded,
|
||||||
size: 56.w,
|
size: 56.w,
|
||||||
|
|
@ -69,10 +72,10 @@ class _LoginScreenState extends State<LoginScreen> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: 16.h),
|
SizedBox(height: 16.h),
|
||||||
Text('LuckyChit', style: AppText.headline(context), textAlign: TextAlign.center),
|
Text(l.appDisplayName, style: AppText.headline(context), textAlign: TextAlign.center),
|
||||||
SizedBox(height: 6.h),
|
SizedBox(height: 6.h),
|
||||||
Text(
|
Text(
|
||||||
'Chit fund management that feels effortless.',
|
l.authLoginTagline,
|
||||||
style: AppText.bodyMuted(context),
|
style: AppText.bodyMuted(context),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
|
|
@ -82,13 +85,13 @@ class _LoginScreenState extends State<LoginScreen> {
|
||||||
controller: _mobileController,
|
controller: _mobileController,
|
||||||
keyboardType: TextInputType.phone,
|
keyboardType: TextInputType.phone,
|
||||||
textInputAction: TextInputAction.next,
|
textInputAction: TextInputAction.next,
|
||||||
decoration: const InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: 'Mobile number',
|
labelText: l.labelMobileNumber,
|
||||||
prefixIcon: Icon(Icons.phone_rounded),
|
prefixIcon: const Icon(Icons.phone_rounded),
|
||||||
),
|
),
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
if (value == null || value.isEmpty) return 'Please enter mobile number';
|
if (value == null || value.isEmpty) return l.validatorEnterMobile;
|
||||||
if (value.length != 10) return 'Mobile number must be 10 digits';
|
if (value.length != 10) return l.validatorMobileTenDigits;
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
@ -98,17 +101,17 @@ class _LoginScreenState extends State<LoginScreen> {
|
||||||
obscureText: !_isPasswordVisible,
|
obscureText: !_isPasswordVisible,
|
||||||
textInputAction: TextInputAction.done,
|
textInputAction: TextInputAction.done,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: 'Password',
|
labelText: l.labelPassword,
|
||||||
prefixIcon: const Icon(Icons.lock_rounded),
|
prefixIcon: const Icon(Icons.lock_rounded),
|
||||||
suffixIcon: IconButton(
|
suffixIcon: IconButton(
|
||||||
tooltip: _isPasswordVisible ? 'Hide password' : 'Show password',
|
tooltip: _isPasswordVisible ? l.tooltipHidePassword : l.tooltipShowPassword,
|
||||||
icon: Icon(_isPasswordVisible ? Icons.visibility : Icons.visibility_off),
|
icon: Icon(_isPasswordVisible ? Icons.visibility : Icons.visibility_off),
|
||||||
onPressed: () => setState(() => _isPasswordVisible = !_isPasswordVisible),
|
onPressed: () => setState(() => _isPasswordVisible = !_isPasswordVisible),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
if (value == null || value.isEmpty) return 'Please enter password';
|
if (value == null || value.isEmpty) return l.validatorEnterPasswordAuth;
|
||||||
if (value.length < 6) return 'Password must be at least 6 characters';
|
if (value.length < 6) return l.validatorPasswordMinSixAuth;
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
@ -127,13 +130,13 @@ class _LoginScreenState extends State<LoginScreen> {
|
||||||
valueColor: AlwaysStoppedAnimation<Color>(scheme.onPrimary),
|
valueColor: AlwaysStoppedAnimation<Color>(scheme.onPrimary),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: const Text('Sign in'),
|
: Text(l.signInButton),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
SizedBox(height: 10.h),
|
SizedBox(height: 10.h),
|
||||||
OutlinedButton(
|
OutlinedButton(
|
||||||
onPressed: () => Get.to(() => const SignupScreen()),
|
onPressed: () => Get.to(() => const SignupScreen()),
|
||||||
child: const Text('Create account'),
|
child: Text(l.createAccountButton),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,14 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
|
import '../../../app.dart';
|
||||||
import '../../../core/services/auth_service.dart';
|
import '../../../core/services/auth_service.dart';
|
||||||
import '../../../core/utils/snackbar_util.dart';
|
import '../../../core/utils/snackbar_util.dart';
|
||||||
import '../../../app.dart';
|
|
||||||
import '../../../core/design_system/app_components/auth_shell.dart';
|
import '../../../core/design_system/app_components/auth_shell.dart';
|
||||||
import '../../../core/design_system/app_components/app_card.dart';
|
import '../../../core/design_system/app_components/app_card.dart';
|
||||||
import '../../../core/design_system/app_spacing.dart';
|
import '../../../core/design_system/app_spacing.dart';
|
||||||
import '../../../core/design_system/app_text.dart';
|
import '../../../core/design_system/app_text.dart';
|
||||||
|
import '../../../l10n/l10n_x.dart';
|
||||||
|
|
||||||
class SignupScreen extends StatefulWidget {
|
class SignupScreen extends StatefulWidget {
|
||||||
const SignupScreen({super.key});
|
const SignupScreen({super.key});
|
||||||
|
|
@ -52,19 +53,19 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||||
emergencyContact: _emergencyContactController.text.trim().isEmpty ? null : _emergencyContactController.text.trim(),
|
emergencyContact: _emergencyContactController.text.trim().isEmpty ? null : _emergencyContactController.text.trim(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!mounted) return;
|
||||||
|
final l = context.l10n;
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
SnackbarUtil.showSuccess(
|
SnackbarUtil.showSuccess(
|
||||||
'Account created successfully! Welcome to LuckyChit.',
|
l.signupSuccessWelcome,
|
||||||
title: 'Success',
|
title: l.snackTitleSuccess,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Navigate to home - App widget will auto-route based on role
|
|
||||||
// Use offAll to remove all previous routes (can't go back to signup)
|
|
||||||
Get.offAll(() => const App());
|
Get.offAll(() => const App());
|
||||||
} else {
|
} else {
|
||||||
SnackbarUtil.showError(
|
SnackbarUtil.showError(
|
||||||
'Failed to create account. Please try again.',
|
l.signupFailedGenericUi,
|
||||||
title: 'Signup Failed',
|
title: l.signupFailedTitle,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -72,6 +73,7 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final l = context.l10n;
|
||||||
final scheme = Theme.of(context).colorScheme;
|
final scheme = Theme.of(context).colorScheme;
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: AuthShell(
|
body: AuthShell(
|
||||||
|
|
@ -90,206 +92,184 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||||
color: scheme.primary,
|
color: scheme.primary,
|
||||||
),
|
),
|
||||||
SizedBox(height: 16.h),
|
SizedBox(height: 16.h),
|
||||||
Text('Create account', style: AppText.headline(context), textAlign: TextAlign.center),
|
Text(l.authSignupScreenTitle, style: AppText.headline(context), textAlign: TextAlign.center),
|
||||||
SizedBox(height: 6.h),
|
SizedBox(height: 6.h),
|
||||||
Text(
|
Text(
|
||||||
'Set up your profile in under a minute.',
|
l.authSignupTagline,
|
||||||
style: AppText.bodyMuted(context),
|
style: AppText.bodyMuted(context),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
SizedBox(height: 24.h),
|
SizedBox(height: 24.h),
|
||||||
|
TextFormField(
|
||||||
// Mobile Number Field
|
controller: _mobileController,
|
||||||
TextFormField(
|
keyboardType: TextInputType.phone,
|
||||||
controller: _mobileController,
|
textInputAction: TextInputAction.next,
|
||||||
keyboardType: TextInputType.phone,
|
decoration: InputDecoration(
|
||||||
textInputAction: TextInputAction.next,
|
labelText: l.labelMobileNumberRequired,
|
||||||
decoration: const InputDecoration(
|
prefixIcon: const Icon(Icons.phone_rounded),
|
||||||
labelText: 'Mobile number *',
|
),
|
||||||
prefixIcon: Icon(Icons.phone_rounded),
|
validator: (value) {
|
||||||
),
|
if (value == null || value.isEmpty) {
|
||||||
validator: (value) {
|
return l.validatorEnterMobile;
|
||||||
if (value == null || value.isEmpty) {
|
}
|
||||||
return 'Please enter mobile number';
|
if (value.length != 10) {
|
||||||
}
|
return l.validatorMobileTenDigits;
|
||||||
if (value.length != 10) {
|
}
|
||||||
return 'Mobile number must be 10 digits';
|
if (!RegExp(r'^[0-9]+$').hasMatch(value)) {
|
||||||
}
|
return l.validatorMobileDigitsOnly;
|
||||||
if (!RegExp(r'^[0-9]+$').hasMatch(value)) {
|
}
|
||||||
return 'Mobile number must contain only digits';
|
return null;
|
||||||
}
|
},
|
||||||
return null;
|
),
|
||||||
},
|
SizedBox(height: 20.h),
|
||||||
),
|
TextFormField(
|
||||||
SizedBox(height: 20.h),
|
controller: _fullNameController,
|
||||||
|
keyboardType: TextInputType.name,
|
||||||
// Full Name Field
|
textInputAction: TextInputAction.next,
|
||||||
TextFormField(
|
decoration: InputDecoration(
|
||||||
controller: _fullNameController,
|
labelText: l.labelFullNameRequired,
|
||||||
keyboardType: TextInputType.name,
|
prefixIcon: const Icon(Icons.person_rounded),
|
||||||
textInputAction: TextInputAction.next,
|
),
|
||||||
decoration: const InputDecoration(
|
validator: (value) {
|
||||||
labelText: 'Full name *',
|
if (value == null || value.isEmpty) {
|
||||||
prefixIcon: Icon(Icons.person_rounded),
|
return l.validatorEnterFullName;
|
||||||
),
|
}
|
||||||
validator: (value) {
|
return null;
|
||||||
if (value == null || value.isEmpty) {
|
},
|
||||||
return 'Please enter your full name';
|
),
|
||||||
}
|
SizedBox(height: 20.h),
|
||||||
return null;
|
TextFormField(
|
||||||
},
|
controller: _emailController,
|
||||||
),
|
keyboardType: TextInputType.emailAddress,
|
||||||
SizedBox(height: 20.h),
|
textInputAction: TextInputAction.next,
|
||||||
|
decoration: InputDecoration(
|
||||||
// Email Field (Optional)
|
labelText: l.labelEmailOptional,
|
||||||
TextFormField(
|
prefixIcon: const Icon(Icons.email_rounded),
|
||||||
controller: _emailController,
|
),
|
||||||
keyboardType: TextInputType.emailAddress,
|
validator: (value) {
|
||||||
textInputAction: TextInputAction.next,
|
if (value != null && value.isNotEmpty) {
|
||||||
decoration: const InputDecoration(
|
if (!RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(value)) {
|
||||||
labelText: 'Email (optional)',
|
return l.validatorValidEmail;
|
||||||
prefixIcon: Icon(Icons.email_rounded),
|
}
|
||||||
),
|
}
|
||||||
validator: (value) {
|
return null;
|
||||||
if (value != null && value.isNotEmpty) {
|
},
|
||||||
if (!RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(value)) {
|
),
|
||||||
return 'Please enter a valid email address';
|
SizedBox(height: 20.h),
|
||||||
}
|
TextFormField(
|
||||||
}
|
controller: _addressController,
|
||||||
return null;
|
keyboardType: TextInputType.streetAddress,
|
||||||
},
|
maxLines: 2,
|
||||||
),
|
textInputAction: TextInputAction.newline,
|
||||||
SizedBox(height: 20.h),
|
decoration: InputDecoration(
|
||||||
|
labelText: l.labelAddressOptional,
|
||||||
// Address Field (Optional)
|
prefixIcon: const Icon(Icons.home_rounded),
|
||||||
TextFormField(
|
),
|
||||||
controller: _addressController,
|
),
|
||||||
keyboardType: TextInputType.streetAddress,
|
SizedBox(height: 20.h),
|
||||||
maxLines: 2,
|
TextFormField(
|
||||||
textInputAction: TextInputAction.newline,
|
controller: _emergencyContactController,
|
||||||
decoration: const InputDecoration(
|
keyboardType: TextInputType.phone,
|
||||||
labelText: 'Address (optional)',
|
textInputAction: TextInputAction.next,
|
||||||
prefixIcon: Icon(Icons.home_rounded),
|
decoration: InputDecoration(
|
||||||
),
|
labelText: l.labelEmergencyContactOptional,
|
||||||
),
|
prefixIcon: const Icon(Icons.contact_phone_rounded),
|
||||||
SizedBox(height: 20.h),
|
),
|
||||||
|
validator: (value) {
|
||||||
// Emergency Contact Field (Optional)
|
if (value != null && value.isNotEmpty) {
|
||||||
TextFormField(
|
if (value.length != 10) {
|
||||||
controller: _emergencyContactController,
|
return l.validatorEmergencyTenDigits;
|
||||||
keyboardType: TextInputType.phone,
|
}
|
||||||
textInputAction: TextInputAction.next,
|
if (!RegExp(r'^[0-9]+$').hasMatch(value)) {
|
||||||
decoration: const InputDecoration(
|
return l.validatorEmergencyDigitsOnly;
|
||||||
labelText: 'Emergency contact (optional)',
|
}
|
||||||
prefixIcon: Icon(Icons.contact_phone_rounded),
|
}
|
||||||
),
|
return null;
|
||||||
validator: (value) {
|
},
|
||||||
if (value != null && value.isNotEmpty) {
|
),
|
||||||
if (value.length != 10) {
|
SizedBox(height: 20.h),
|
||||||
return 'Emergency contact must be 10 digits';
|
TextFormField(
|
||||||
}
|
controller: _passwordController,
|
||||||
if (!RegExp(r'^[0-9]+$').hasMatch(value)) {
|
obscureText: !_isPasswordVisible,
|
||||||
return 'Emergency contact must contain only digits';
|
textInputAction: TextInputAction.next,
|
||||||
}
|
decoration: InputDecoration(
|
||||||
}
|
labelText: l.labelPasswordRequired,
|
||||||
return null;
|
prefixIcon: const Icon(Icons.lock_rounded),
|
||||||
},
|
suffixIcon: IconButton(
|
||||||
),
|
tooltip: _isPasswordVisible ? l.tooltipHidePassword : l.tooltipShowPassword,
|
||||||
SizedBox(height: 20.h),
|
icon: Icon(_isPasswordVisible ? Icons.visibility : Icons.visibility_off),
|
||||||
|
onPressed: () => setState(() => _isPasswordVisible = !_isPasswordVisible),
|
||||||
// Password Field
|
),
|
||||||
TextFormField(
|
),
|
||||||
controller: _passwordController,
|
validator: (value) {
|
||||||
obscureText: !_isPasswordVisible,
|
if (value == null || value.isEmpty) {
|
||||||
textInputAction: TextInputAction.next,
|
return l.validatorEnterPasswordAuth;
|
||||||
decoration: InputDecoration(
|
}
|
||||||
labelText: 'Password *',
|
if (value.length < 6) {
|
||||||
prefixIcon: const Icon(Icons.lock_rounded),
|
return l.validatorPasswordMinSixAuth;
|
||||||
suffixIcon: IconButton(
|
}
|
||||||
tooltip: _isPasswordVisible ? 'Hide password' : 'Show password',
|
return null;
|
||||||
icon: Icon(_isPasswordVisible ? Icons.visibility : Icons.visibility_off),
|
},
|
||||||
onPressed: () => setState(() => _isPasswordVisible = !_isPasswordVisible),
|
),
|
||||||
),
|
SizedBox(height: 20.h),
|
||||||
),
|
TextFormField(
|
||||||
validator: (value) {
|
controller: _confirmPasswordController,
|
||||||
if (value == null || value.isEmpty) {
|
obscureText: !_isConfirmPasswordVisible,
|
||||||
return 'Please enter password';
|
textInputAction: TextInputAction.done,
|
||||||
}
|
decoration: InputDecoration(
|
||||||
if (value.length < 6) {
|
labelText: l.labelConfirmPasswordRequired,
|
||||||
return 'Password must be at least 6 characters';
|
prefixIcon: const Icon(Icons.lock_outline_rounded),
|
||||||
}
|
suffixIcon: IconButton(
|
||||||
return null;
|
tooltip: _isConfirmPasswordVisible ? l.tooltipHidePassword : l.tooltipShowPassword,
|
||||||
},
|
icon: Icon(_isConfirmPasswordVisible ? Icons.visibility : Icons.visibility_off),
|
||||||
),
|
onPressed: () => setState(() => _isConfirmPasswordVisible = !_isConfirmPasswordVisible),
|
||||||
SizedBox(height: 20.h),
|
),
|
||||||
|
),
|
||||||
// Confirm Password Field
|
validator: (value) {
|
||||||
TextFormField(
|
if (value == null || value.isEmpty) {
|
||||||
controller: _confirmPasswordController,
|
return l.validatorConfirmPassword;
|
||||||
obscureText: !_isConfirmPasswordVisible,
|
}
|
||||||
textInputAction: TextInputAction.done,
|
if (value != _passwordController.text) {
|
||||||
decoration: InputDecoration(
|
return l.validatorPasswordsMismatch;
|
||||||
labelText: 'Confirm password *',
|
}
|
||||||
prefixIcon: const Icon(Icons.lock_outline_rounded),
|
return null;
|
||||||
suffixIcon: IconButton(
|
},
|
||||||
tooltip: _isConfirmPasswordVisible ? 'Hide password' : 'Show password',
|
),
|
||||||
icon: Icon(_isConfirmPasswordVisible ? Icons.visibility : Icons.visibility_off),
|
SizedBox(height: 28.h),
|
||||||
onPressed: () => setState(() => _isConfirmPasswordVisible = !_isConfirmPasswordVisible),
|
Obx(() => SizedBox(
|
||||||
),
|
width: double.infinity,
|
||||||
),
|
height: 52.h,
|
||||||
validator: (value) {
|
child: FilledButton(
|
||||||
if (value == null || value.isEmpty) {
|
onPressed: _authService.isLoading.value ? null : _handleSignup,
|
||||||
return 'Please confirm password';
|
child: _authService.isLoading.value
|
||||||
}
|
? SizedBox(
|
||||||
if (value != _passwordController.text) {
|
height: 24.h,
|
||||||
return 'Passwords do not match';
|
width: 24.w,
|
||||||
}
|
child: CircularProgressIndicator(
|
||||||
return null;
|
strokeWidth: 2,
|
||||||
},
|
valueColor: AlwaysStoppedAnimation<Color>(scheme.onPrimary),
|
||||||
),
|
),
|
||||||
SizedBox(height: 28.h),
|
)
|
||||||
|
: Text(l.createAccountButton),
|
||||||
// Signup Button
|
),
|
||||||
Obx(() => SizedBox(
|
)),
|
||||||
width: double.infinity,
|
SizedBox(height: 20.h),
|
||||||
height: 52.h,
|
Row(
|
||||||
child: FilledButton(
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
onPressed: _authService.isLoading.value
|
children: [
|
||||||
? null
|
Text(
|
||||||
: _handleSignup,
|
l.alreadyHaveAccount,
|
||||||
child: _authService.isLoading.value
|
style: AppText.bodyMuted(context),
|
||||||
? SizedBox(
|
),
|
||||||
height: 24.h,
|
TextButton(
|
||||||
width: 24.w,
|
onPressed: () => Get.back(),
|
||||||
child: CircularProgressIndicator(
|
child: Text(
|
||||||
strokeWidth: 2,
|
l.loginLink,
|
||||||
valueColor: AlwaysStoppedAnimation<Color>(scheme.onPrimary),
|
style: AppText.label(context).copyWith(color: scheme.primary),
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
: const Text('Create account'),
|
],
|
||||||
),
|
),
|
||||||
)),
|
|
||||||
SizedBox(height: 20.h),
|
|
||||||
|
|
||||||
// Login Link
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'Already have an account? ',
|
|
||||||
style: AppText.bodyMuted(context),
|
|
||||||
),
|
|
||||||
TextButton(
|
|
||||||
onPressed: () {
|
|
||||||
Get.back();
|
|
||||||
},
|
|
||||||
child: Text(
|
|
||||||
'Login',
|
|
||||||
style: AppText.label(context).copyWith(color: scheme.primary),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -299,4 +279,3 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,27 +3,44 @@ import 'package:flutter/services.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
import '../../core/controllers/theme_controller.dart';
|
import '../../core/controllers/theme_controller.dart';
|
||||||
|
import '../../core/controllers/locale_controller.dart';
|
||||||
import '../../core/services/auth_service.dart';
|
import '../../core/services/auth_service.dart';
|
||||||
import '../../core/services/api_service.dart';
|
import '../../core/services/api_service.dart';
|
||||||
import '../../core/utils/snackbar_util.dart';
|
import '../../core/utils/snackbar_util.dart';
|
||||||
|
import '../../l10n/app_localizations.dart';
|
||||||
|
|
||||||
|
String _themeModeLabel(AppLocalizations l10n) {
|
||||||
|
switch (ThemeController.to.themeMode) {
|
||||||
|
case ThemeMode.light:
|
||||||
|
return l10n.themeLight;
|
||||||
|
case ThemeMode.dark:
|
||||||
|
return l10n.themeDark;
|
||||||
|
case ThemeMode.system:
|
||||||
|
return l10n.themeSystem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class SettingsPage extends StatelessWidget {
|
class SettingsPage extends StatelessWidget {
|
||||||
const SettingsPage({super.key});
|
const SettingsPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final l10n = AppLocalizations.of(context);
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: const Text('Settings'),
|
title: Text(l10n.settingsTitle),
|
||||||
),
|
),
|
||||||
body: ListView(
|
body: ListView(
|
||||||
padding: EdgeInsets.all(16.w),
|
padding: EdgeInsets.all(16.w),
|
||||||
children: [
|
children: [
|
||||||
_buildSectionHeader(context, 'Appearance'),
|
_buildSectionHeader(context, l10n.sectionAppearance),
|
||||||
_buildThemeSettings(context),
|
_buildThemeSettings(context, l10n),
|
||||||
SizedBox(height: 24.h),
|
SizedBox(height: 24.h),
|
||||||
_buildSectionHeader(context, 'Account'),
|
_buildSectionHeader(context, l10n.sectionLanguage),
|
||||||
_buildAccountSettings(context),
|
_buildLanguageSettings(context, l10n),
|
||||||
|
SizedBox(height: 24.h),
|
||||||
|
_buildSectionHeader(context, l10n.sectionAccount),
|
||||||
|
_buildAccountSettings(context, l10n),
|
||||||
SizedBox(height: 24.h),
|
SizedBox(height: 24.h),
|
||||||
Obx(() {
|
Obx(() {
|
||||||
final user = AuthService.to.currentUser.value;
|
final user = AuthService.to.currentUser.value;
|
||||||
|
|
@ -31,21 +48,21 @@ class SettingsPage extends StatelessWidget {
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
_buildSectionHeader(context, 'Payment Settings'),
|
_buildSectionHeader(context, l10n.sectionPaymentSettings),
|
||||||
_buildPaymentSettings(context),
|
_buildPaymentSettings(context, l10n),
|
||||||
SizedBox(height: 24.h),
|
SizedBox(height: 24.h),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
}),
|
}),
|
||||||
_buildSectionHeader(context, 'Notifications'),
|
_buildSectionHeader(context, l10n.sectionNotifications),
|
||||||
_buildNotificationSettings(context),
|
_buildNotificationSettings(context, l10n),
|
||||||
SizedBox(height: 24.h),
|
SizedBox(height: 24.h),
|
||||||
_buildSectionHeader(context, 'About'),
|
_buildSectionHeader(context, l10n.sectionAbout),
|
||||||
_buildAboutSettings(context),
|
_buildAboutSettings(context, l10n),
|
||||||
SizedBox(height: 32.h),
|
SizedBox(height: 32.h),
|
||||||
_buildLogoutButton(context),
|
_buildLogoutButton(context, l10n),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
@ -67,13 +84,88 @@ class SettingsPage extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildThemeSettings(BuildContext context) {
|
Widget _buildLanguageSettings(BuildContext context, AppLocalizations l10n) {
|
||||||
|
final scheme = Theme.of(context).colorScheme;
|
||||||
|
return Card(
|
||||||
|
child: Obx(
|
||||||
|
() => ListTile(
|
||||||
|
leading: Container(
|
||||||
|
padding: EdgeInsets.all(10.w),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: scheme.secondaryContainer,
|
||||||
|
borderRadius: BorderRadius.circular(12.r),
|
||||||
|
),
|
||||||
|
child: Icon(
|
||||||
|
Icons.language_rounded,
|
||||||
|
color: scheme.onSecondaryContainer,
|
||||||
|
size: 24.w,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
l10n.languageTitle,
|
||||||
|
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600),
|
||||||
|
),
|
||||||
|
subtitle: Text(
|
||||||
|
LocaleController.to.currentLanguageLabel(l10n),
|
||||||
|
style: TextStyle(fontSize: 14.sp),
|
||||||
|
),
|
||||||
|
trailing: Icon(Icons.arrow_forward_ios_rounded, size: 16.w),
|
||||||
|
onTap: () => _showLanguageDialog(context, l10n),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _showLanguageDialog(BuildContext context, AppLocalizations l10n) {
|
||||||
|
final scheme = Theme.of(context).colorScheme;
|
||||||
|
Get.dialog(
|
||||||
|
Obx(
|
||||||
|
() {
|
||||||
|
final code = LocaleController.to.locale.value.languageCode;
|
||||||
|
return AlertDialog(
|
||||||
|
title: Text(l10n.chooseLanguageTitle),
|
||||||
|
content: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
RadioListTile<String>(
|
||||||
|
title: Text(l10n.languageEnglish),
|
||||||
|
value: 'en',
|
||||||
|
groupValue: code,
|
||||||
|
onChanged: (v) async {
|
||||||
|
if (v != null) {
|
||||||
|
await LocaleController.to.setLocale(Locale(v));
|
||||||
|
Get.back();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
activeColor: scheme.primary,
|
||||||
|
),
|
||||||
|
RadioListTile<String>(
|
||||||
|
title: Text(l10n.languageTelugu),
|
||||||
|
value: 'te',
|
||||||
|
groupValue: code,
|
||||||
|
onChanged: (v) async {
|
||||||
|
if (v != null) {
|
||||||
|
await LocaleController.to.setLocale(Locale(v));
|
||||||
|
Get.back();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
activeColor: scheme.primary,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildThemeSettings(BuildContext context, AppLocalizations l10n) {
|
||||||
final scheme = Theme.of(context).colorScheme;
|
final scheme = Theme.of(context).colorScheme;
|
||||||
return Card(
|
return Card(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Obx(() {
|
Obx(
|
||||||
return ListTile(
|
() => ListTile(
|
||||||
leading: Container(
|
leading: Container(
|
||||||
padding: EdgeInsets.all(10.w),
|
padding: EdgeInsets.all(10.w),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
|
|
@ -87,22 +179,20 @@ class SettingsPage extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
'Theme',
|
l10n.themeTitle,
|
||||||
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600),
|
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600),
|
||||||
),
|
),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
ThemeController.to.getThemeModeString(),
|
_themeModeLabel(l10n),
|
||||||
style: TextStyle(fontSize: 14.sp),
|
style: TextStyle(fontSize: 14.sp),
|
||||||
),
|
),
|
||||||
trailing: Icon(Icons.arrow_forward_ios_rounded, size: 16.w),
|
trailing: Icon(Icons.arrow_forward_ios_rounded, size: 16.w),
|
||||||
onTap: () => _showThemeDialog(context),
|
onTap: () => _showThemeDialog(context, l10n),
|
||||||
);
|
),
|
||||||
}),
|
),
|
||||||
|
|
||||||
Divider(height: 1.h, indent: 72.w),
|
Divider(height: 1.h, indent: 72.w),
|
||||||
|
Obx(
|
||||||
Obx(() {
|
() => SwitchListTile(
|
||||||
return SwitchListTile(
|
|
||||||
secondary: Container(
|
secondary: Container(
|
||||||
padding: EdgeInsets.all(10.w),
|
padding: EdgeInsets.all(10.w),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
|
|
@ -116,11 +206,11 @@ class SettingsPage extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
'Dark Mode',
|
l10n.darkModeTitle,
|
||||||
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600),
|
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600),
|
||||||
),
|
),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
'Override system settings',
|
l10n.darkModeSubtitle,
|
||||||
style: TextStyle(fontSize: 14.sp),
|
style: TextStyle(fontSize: 14.sp),
|
||||||
),
|
),
|
||||||
value: ThemeController.to.isDarkMode,
|
value: ThemeController.to.isDarkMode,
|
||||||
|
|
@ -128,51 +218,50 @@ class SettingsPage extends StatelessWidget {
|
||||||
ThemeController.to.toggleTheme();
|
ThemeController.to.toggleTheme();
|
||||||
},
|
},
|
||||||
activeColor: scheme.primary,
|
activeColor: scheme.primary,
|
||||||
);
|
),
|
||||||
}),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildAccountSettings(BuildContext context) {
|
Widget _buildAccountSettings(BuildContext context, AppLocalizations l10n) {
|
||||||
final scheme = Theme.of(context).colorScheme;
|
final scheme = Theme.of(context).colorScheme;
|
||||||
return Card(
|
return Card(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Obx(() {
|
Obx(
|
||||||
final user = AuthService.to.currentUser.value;
|
() {
|
||||||
return ListTile(
|
final user = AuthService.to.currentUser.value;
|
||||||
leading: Container(
|
return ListTile(
|
||||||
padding: EdgeInsets.all(10.w),
|
leading: Container(
|
||||||
decoration: BoxDecoration(
|
padding: EdgeInsets.all(10.w),
|
||||||
color: scheme.primaryContainer,
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(12.r),
|
color: scheme.primaryContainer,
|
||||||
|
borderRadius: BorderRadius.circular(12.r),
|
||||||
|
),
|
||||||
|
child: Icon(
|
||||||
|
Icons.person_rounded,
|
||||||
|
color: scheme.onPrimaryContainer,
|
||||||
|
size: 24.w,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
child: Icon(
|
title: Text(
|
||||||
Icons.person_rounded,
|
user?.fullName ?? 'User',
|
||||||
color: scheme.onPrimaryContainer,
|
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600),
|
||||||
size: 24.w,
|
|
||||||
),
|
),
|
||||||
),
|
subtitle: Text(
|
||||||
title: Text(
|
user?.mobileNumber ?? '',
|
||||||
user?.fullName ?? 'User',
|
style: TextStyle(fontSize: 14.sp),
|
||||||
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600),
|
),
|
||||||
),
|
trailing: Icon(Icons.arrow_forward_ios_rounded, size: 16.w),
|
||||||
subtitle: Text(
|
onTap: () {
|
||||||
user?.mobileNumber ?? '',
|
SnackbarUtil.showInfo(l10n.profileComingSoon);
|
||||||
style: TextStyle(fontSize: 14.sp),
|
},
|
||||||
),
|
);
|
||||||
trailing: Icon(Icons.arrow_forward_ios_rounded, size: 16.w),
|
},
|
||||||
onTap: () {
|
),
|
||||||
SnackbarUtil.showInfo('Profile page coming soon');
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
|
|
||||||
Divider(height: 1.h, indent: 72.w),
|
Divider(height: 1.h, indent: 72.w),
|
||||||
|
|
||||||
// Change Password
|
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: Container(
|
leading: Container(
|
||||||
padding: EdgeInsets.all(10.w),
|
padding: EdgeInsets.all(10.w),
|
||||||
|
|
@ -187,16 +276,16 @@ class SettingsPage extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
'Change Password',
|
l10n.changePasswordTitle,
|
||||||
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600),
|
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600),
|
||||||
),
|
),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
'Update your password',
|
l10n.changePasswordSubtitle,
|
||||||
style: TextStyle(fontSize: 14.sp),
|
style: TextStyle(fontSize: 14.sp),
|
||||||
),
|
),
|
||||||
trailing: Icon(Icons.arrow_forward_ios_rounded, size: 16.w),
|
trailing: Icon(Icons.arrow_forward_ios_rounded, size: 16.w),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
SnackbarUtil.showInfo('Change password feature coming soon');
|
SnackbarUtil.showInfo(l10n.changePasswordComingSoon);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
@ -204,7 +293,8 @@ class SettingsPage extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildNotificationSettings(BuildContext context) {
|
Widget _buildNotificationSettings(
|
||||||
|
BuildContext context, AppLocalizations l10n) {
|
||||||
final scheme = Theme.of(context).colorScheme;
|
final scheme = Theme.of(context).colorScheme;
|
||||||
return Card(
|
return Card(
|
||||||
child: Column(
|
child: Column(
|
||||||
|
|
@ -223,22 +313,20 @@ class SettingsPage extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
'Push Notifications',
|
l10n.pushNotificationsTitle,
|
||||||
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600),
|
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600),
|
||||||
),
|
),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
'Receive push notifications',
|
l10n.pushNotificationsSubtitle,
|
||||||
style: TextStyle(fontSize: 14.sp),
|
style: TextStyle(fontSize: 14.sp),
|
||||||
),
|
),
|
||||||
value: true,
|
value: true,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
SnackbarUtil.showInfo('Notification settings coming soon');
|
SnackbarUtil.showInfo(l10n.notificationComingSoon);
|
||||||
},
|
},
|
||||||
activeColor: scheme.primary,
|
activeColor: scheme.primary,
|
||||||
),
|
),
|
||||||
|
|
||||||
Divider(height: 1.h, indent: 72.w),
|
Divider(height: 1.h, indent: 72.w),
|
||||||
|
|
||||||
SwitchListTile(
|
SwitchListTile(
|
||||||
secondary: Container(
|
secondary: Container(
|
||||||
padding: EdgeInsets.all(10.w),
|
padding: EdgeInsets.all(10.w),
|
||||||
|
|
@ -253,22 +341,20 @@ class SettingsPage extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
'Payment Reminders',
|
l10n.paymentRemindersTitle,
|
||||||
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600),
|
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600),
|
||||||
),
|
),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
'Reminders for upcoming payments',
|
l10n.paymentRemindersSubtitle,
|
||||||
style: TextStyle(fontSize: 14.sp),
|
style: TextStyle(fontSize: 14.sp),
|
||||||
),
|
),
|
||||||
value: true,
|
value: true,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
SnackbarUtil.showInfo('Notification settings coming soon');
|
SnackbarUtil.showInfo(l10n.notificationComingSoon);
|
||||||
},
|
},
|
||||||
activeColor: scheme.primary,
|
activeColor: scheme.primary,
|
||||||
),
|
),
|
||||||
|
|
||||||
Divider(height: 1.h, indent: 72.w),
|
Divider(height: 1.h, indent: 72.w),
|
||||||
|
|
||||||
SwitchListTile(
|
SwitchListTile(
|
||||||
secondary: Container(
|
secondary: Container(
|
||||||
padding: EdgeInsets.all(10.w),
|
padding: EdgeInsets.all(10.w),
|
||||||
|
|
@ -283,16 +369,16 @@ class SettingsPage extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
'Draw Notifications',
|
l10n.drawNotificationsTitle,
|
||||||
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600),
|
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600),
|
||||||
),
|
),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
'Alerts for lottery draws',
|
l10n.drawNotificationsSubtitle,
|
||||||
style: TextStyle(fontSize: 14.sp),
|
style: TextStyle(fontSize: 14.sp),
|
||||||
),
|
),
|
||||||
value: true,
|
value: true,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
SnackbarUtil.showInfo('Notification settings coming soon');
|
SnackbarUtil.showInfo(l10n.notificationComingSoon);
|
||||||
},
|
},
|
||||||
activeColor: scheme.primary,
|
activeColor: scheme.primary,
|
||||||
),
|
),
|
||||||
|
|
@ -301,7 +387,7 @@ class SettingsPage extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildPaymentSettings(BuildContext context) {
|
Widget _buildPaymentSettings(BuildContext context, AppLocalizations l10n) {
|
||||||
final apiService = ApiService();
|
final apiService = ApiService();
|
||||||
final scheme = Theme.of(context).colorScheme;
|
final scheme = Theme.of(context).colorScheme;
|
||||||
|
|
||||||
|
|
@ -326,17 +412,17 @@ class SettingsPage extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
'UPI ID',
|
l10n.upiIdTitle,
|
||||||
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600),
|
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600),
|
||||||
),
|
),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
'Loading...',
|
l10n.loading,
|
||||||
style: TextStyle(fontSize: 14.sp),
|
style: TextStyle(fontSize: 14.sp),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final upiId = snapshot.data?['data']?['upi_id'] ?? 'Not configured';
|
final upiId = snapshot.data?['data']?['upi_id'] ?? l10n.notConfigured;
|
||||||
final isConfigured = snapshot.data?['data']?['is_configured'] ?? false;
|
final isConfigured = snapshot.data?['data']?['is_configured'] ?? false;
|
||||||
|
|
||||||
return ListTile(
|
return ListTile(
|
||||||
|
|
@ -359,7 +445,7 @@ class SettingsPage extends StatelessWidget {
|
||||||
title: Row(
|
title: Row(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'UPI ID',
|
l10n.upiIdTitle,
|
||||||
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600),
|
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600),
|
||||||
),
|
),
|
||||||
if (isConfigured) ...[
|
if (isConfigured) ...[
|
||||||
|
|
@ -371,7 +457,7 @@ class SettingsPage extends StatelessWidget {
|
||||||
borderRadius: BorderRadius.circular(12.r),
|
borderRadius: BorderRadius.circular(12.r),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
'Active',
|
l10n.active,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 10.sp,
|
fontSize: 10.sp,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
|
|
@ -387,7 +473,7 @@ class SettingsPage extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
SizedBox(height: 4.h),
|
SizedBox(height: 4.h),
|
||||||
SelectableText(
|
SelectableText(
|
||||||
upiId,
|
upiId.toString(),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14.sp,
|
fontSize: 14.sp,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
|
|
@ -400,7 +486,7 @@ class SettingsPage extends StatelessWidget {
|
||||||
if (!isConfigured) ...[
|
if (!isConfigured) ...[
|
||||||
SizedBox(height: 4.h),
|
SizedBox(height: 4.h),
|
||||||
Text(
|
Text(
|
||||||
'Configure in backend/.env',
|
l10n.configureBackend,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12.sp,
|
fontSize: 12.sp,
|
||||||
color: scheme.tertiary,
|
color: scheme.tertiary,
|
||||||
|
|
@ -413,29 +499,26 @@ class SettingsPage extends StatelessWidget {
|
||||||
trailing: isConfigured
|
trailing: isConfigured
|
||||||
? IconButton(
|
? IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Clipboard.setData(ClipboardData(text: upiId));
|
Clipboard.setData(ClipboardData(text: upiId.toString()));
|
||||||
SnackbarUtil.showSuccess('UPI ID copied to clipboard');
|
SnackbarUtil.showSuccess(l10n.upiCopiedClipboard);
|
||||||
},
|
},
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
Icons.copy_rounded,
|
Icons.copy_rounded,
|
||||||
size: 20.w,
|
size: 20.w,
|
||||||
color: scheme.secondary,
|
color: scheme.secondary,
|
||||||
),
|
),
|
||||||
tooltip: 'Copy UPI ID',
|
tooltip: l10n.copyUpiIdTooltip,
|
||||||
)
|
)
|
||||||
: Icon(
|
: Icon(
|
||||||
Icons.warning_rounded,
|
Icons.warning_rounded,
|
||||||
size: 20.w,
|
size: 20.w,
|
||||||
color: scheme.tertiary,
|
color: scheme.tertiary,
|
||||||
),
|
),
|
||||||
onTap: () => _showUPIInfoDialog(context, upiId, isConfigured),
|
onTap: () => _showUPIInfoDialog(context, l10n, upiId.toString(), isConfigured),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
||||||
Divider(height: 1.h, indent: 72.w),
|
Divider(height: 1.h, indent: 72.w),
|
||||||
|
|
||||||
// Payment Statistics
|
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: Container(
|
leading: Container(
|
||||||
padding: EdgeInsets.all(10.w),
|
padding: EdgeInsets.all(10.w),
|
||||||
|
|
@ -450,21 +533,19 @@ class SettingsPage extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
'Payment Statistics',
|
l10n.paymentStatisticsTitle,
|
||||||
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600),
|
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600),
|
||||||
),
|
),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
'View payment insights',
|
l10n.paymentStatisticsSubtitle,
|
||||||
style: TextStyle(fontSize: 14.sp),
|
style: TextStyle(fontSize: 14.sp),
|
||||||
),
|
),
|
||||||
trailing: Icon(Icons.arrow_forward_ios_rounded, size: 16.w),
|
trailing: Icon(Icons.arrow_forward_ios_rounded, size: 16.w),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
SnackbarUtil.showInfo('Payment statistics coming soon');
|
SnackbarUtil.showInfo(l10n.paymentStatsComingSoon);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
||||||
Divider(height: 1.h, indent: 72.w),
|
Divider(height: 1.h, indent: 72.w),
|
||||||
|
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: Container(
|
leading: Container(
|
||||||
padding: EdgeInsets.all(10.w),
|
padding: EdgeInsets.all(10.w),
|
||||||
|
|
@ -479,11 +560,11 @@ class SettingsPage extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
'Transaction Fees',
|
l10n.transactionFeesTitle,
|
||||||
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600),
|
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600),
|
||||||
),
|
),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
'0% fees • Save lakhs per year!',
|
l10n.transactionFeesSubtitle,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14.sp,
|
fontSize: 14.sp,
|
||||||
color: scheme.primary,
|
color: scheme.primary,
|
||||||
|
|
@ -497,7 +578,7 @@ class SettingsPage extends StatelessWidget {
|
||||||
borderRadius: BorderRadius.circular(8.r),
|
borderRadius: BorderRadius.circular(8.r),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
'FREE',
|
l10n.free,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12.sp,
|
fontSize: 12.sp,
|
||||||
fontWeight: FontWeight.w800,
|
fontWeight: FontWeight.w800,
|
||||||
|
|
@ -511,7 +592,12 @@ class SettingsPage extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showUPIInfoDialog(BuildContext context, String upiId, bool isConfigured) {
|
void _showUPIInfoDialog(
|
||||||
|
BuildContext context,
|
||||||
|
AppLocalizations l10n,
|
||||||
|
String upiId,
|
||||||
|
bool isConfigured,
|
||||||
|
) {
|
||||||
final scheme = Theme.of(context).colorScheme;
|
final scheme = Theme.of(context).colorScheme;
|
||||||
Get.dialog(
|
Get.dialog(
|
||||||
AlertDialog(
|
AlertDialog(
|
||||||
|
|
@ -523,7 +609,7 @@ class SettingsPage extends StatelessWidget {
|
||||||
size: 24.w,
|
size: 24.w,
|
||||||
),
|
),
|
||||||
SizedBox(width: 12.w),
|
SizedBox(width: 12.w),
|
||||||
const Text('UPI Payment Settings'),
|
Expanded(child: Text(l10n.upiPaymentSettingsTitle)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
content: SingleChildScrollView(
|
content: SingleChildScrollView(
|
||||||
|
|
@ -532,7 +618,7 @@ class SettingsPage extends StatelessWidget {
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Current UPI ID',
|
l10n.currentUpiId,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14.sp,
|
fontSize: 14.sp,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
|
|
@ -573,7 +659,7 @@ class SettingsPage extends StatelessWidget {
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Clipboard.setData(ClipboardData(text: upiId));
|
Clipboard.setData(ClipboardData(text: upiId));
|
||||||
SnackbarUtil.showSuccess('Copied!');
|
SnackbarUtil.showSuccess(l10n.copied);
|
||||||
},
|
},
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
Icons.copy_rounded,
|
Icons.copy_rounded,
|
||||||
|
|
@ -584,7 +670,6 @@ class SettingsPage extends StatelessWidget {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
if (!isConfigured) ...[
|
if (!isConfigured) ...[
|
||||||
SizedBox(height: 16.h),
|
SizedBox(height: 16.h),
|
||||||
Container(
|
Container(
|
||||||
|
|
@ -603,7 +688,7 @@ class SettingsPage extends StatelessWidget {
|
||||||
SizedBox(width: 8.w),
|
SizedBox(width: 8.w),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
'UPI ID not configured. Update backend/.env file.',
|
l10n.upiNotConfiguredMessage,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12.sp,
|
fontSize: 12.sp,
|
||||||
color: scheme.onTertiaryContainer,
|
color: scheme.onTertiaryContainer,
|
||||||
|
|
@ -614,13 +699,11 @@ class SettingsPage extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
||||||
SizedBox(height: 16.h),
|
SizedBox(height: 16.h),
|
||||||
const Divider(),
|
const Divider(),
|
||||||
SizedBox(height: 16.h),
|
SizedBox(height: 16.h),
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
'How to Update UPI ID',
|
l10n.howToUpdateUpi,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14.sp,
|
fontSize: 14.sp,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
|
|
@ -628,11 +711,10 @@ class SettingsPage extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: 12.h),
|
SizedBox(height: 12.h),
|
||||||
_buildInfoStep(context, '1', 'Open backend/.env file'),
|
_buildInfoStep(context, '1', l10n.stepOpenEnv),
|
||||||
_buildInfoStep(context, '2', 'Update PHONEPE_UPI_ID=your_upi@paytm'),
|
_buildInfoStep(context, '2', l10n.stepUpdatePhonepe),
|
||||||
_buildInfoStep(context, '3', 'Restart backend server'),
|
_buildInfoStep(context, '3', l10n.stepRestartBackend),
|
||||||
_buildInfoStep(context, '4', 'Refresh this screen'),
|
_buildInfoStep(context, '4', l10n.stepRefreshScreen),
|
||||||
|
|
||||||
SizedBox(height: 16.h),
|
SizedBox(height: 16.h),
|
||||||
Container(
|
Container(
|
||||||
padding: EdgeInsets.all(12.w),
|
padding: EdgeInsets.all(12.w),
|
||||||
|
|
@ -652,7 +734,7 @@ class SettingsPage extends StatelessWidget {
|
||||||
),
|
),
|
||||||
SizedBox(width: 8.w),
|
SizedBox(width: 8.w),
|
||||||
Text(
|
Text(
|
||||||
'Pro Tip',
|
l10n.proTipTitle,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 13.sp,
|
fontSize: 13.sp,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
|
|
@ -663,7 +745,7 @@ class SettingsPage extends StatelessWidget {
|
||||||
),
|
),
|
||||||
SizedBox(height: 8.h),
|
SizedBox(height: 8.h),
|
||||||
Text(
|
Text(
|
||||||
'Members can pay using ANY UPI app (PhonePe, GPay, Paytm) directly to your personal UPI ID with 0% transaction fees!',
|
l10n.proTipBody,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12.sp,
|
fontSize: 12.sp,
|
||||||
color: scheme.onPrimaryContainer.withOpacity(0.92),
|
color: scheme.onPrimaryContainer.withOpacity(0.92),
|
||||||
|
|
@ -679,7 +761,7 @@ class SettingsPage extends StatelessWidget {
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Get.back(),
|
onPressed: () => Get.back(),
|
||||||
child: const Text('Close'),
|
child: Text(l10n.close),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
@ -730,7 +812,7 @@ class SettingsPage extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildAboutSettings(BuildContext context) {
|
Widget _buildAboutSettings(BuildContext context, AppLocalizations l10n) {
|
||||||
final scheme = Theme.of(context).colorScheme;
|
final scheme = Theme.of(context).colorScheme;
|
||||||
return Card(
|
return Card(
|
||||||
child: Column(
|
child: Column(
|
||||||
|
|
@ -749,7 +831,7 @@ class SettingsPage extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
'App Version',
|
l10n.appVersionTitle,
|
||||||
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600),
|
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600),
|
||||||
),
|
),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
|
|
@ -757,9 +839,7 @@ class SettingsPage extends StatelessWidget {
|
||||||
style: TextStyle(fontSize: 14.sp),
|
style: TextStyle(fontSize: 14.sp),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
Divider(height: 1.h, indent: 72.w),
|
Divider(height: 1.h, indent: 72.w),
|
||||||
|
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: Container(
|
leading: Container(
|
||||||
padding: EdgeInsets.all(10.w),
|
padding: EdgeInsets.all(10.w),
|
||||||
|
|
@ -774,17 +854,15 @@ class SettingsPage extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
'Privacy Policy',
|
l10n.privacyPolicyTitle,
|
||||||
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600),
|
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600),
|
||||||
),
|
),
|
||||||
trailing: Icon(Icons.arrow_forward_ios_rounded, size: 16.w),
|
trailing: Icon(Icons.arrow_forward_ios_rounded, size: 16.w),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
SnackbarUtil.showInfo('Privacy policy page coming soon');
|
SnackbarUtil.showInfo(l10n.privacyComingSoon);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
||||||
Divider(height: 1.h, indent: 72.w),
|
Divider(height: 1.h, indent: 72.w),
|
||||||
|
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: Container(
|
leading: Container(
|
||||||
padding: EdgeInsets.all(10.w),
|
padding: EdgeInsets.all(10.w),
|
||||||
|
|
@ -799,12 +877,12 @@ class SettingsPage extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
'Terms of Service',
|
l10n.termsOfServiceTitle,
|
||||||
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600),
|
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600),
|
||||||
),
|
),
|
||||||
trailing: Icon(Icons.arrow_forward_ios_rounded, size: 16.w),
|
trailing: Icon(Icons.arrow_forward_ios_rounded, size: 16.w),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
SnackbarUtil.showInfo('Terms of service page coming soon');
|
SnackbarUtil.showInfo(l10n.termsComingSoon);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
@ -812,15 +890,15 @@ class SettingsPage extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildLogoutButton(BuildContext context) {
|
Widget _buildLogoutButton(BuildContext context, AppLocalizations l10n) {
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
height: 52.h,
|
height: 52.h,
|
||||||
child: ElevatedButton.icon(
|
child: ElevatedButton.icon(
|
||||||
onPressed: () => _showLogoutDialog(context),
|
onPressed: () => _showLogoutDialog(context, l10n),
|
||||||
icon: Icon(Icons.logout_rounded, size: 20.w),
|
icon: Icon(Icons.logout_rounded, size: 20.w),
|
||||||
label: Text(
|
label: Text(
|
||||||
'Logout',
|
l10n.logout,
|
||||||
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600),
|
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.w600),
|
||||||
),
|
),
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
|
|
@ -834,16 +912,16 @@ class SettingsPage extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showThemeDialog(BuildContext context) {
|
void _showThemeDialog(BuildContext context, AppLocalizations l10n) {
|
||||||
final scheme = Theme.of(context).colorScheme;
|
final scheme = Theme.of(context).colorScheme;
|
||||||
Get.dialog(
|
Get.dialog(
|
||||||
AlertDialog(
|
AlertDialog(
|
||||||
title: const Text('Choose Theme'),
|
title: Text(l10n.chooseThemeTitle),
|
||||||
content: Column(
|
content: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
RadioListTile<ThemeMode>(
|
RadioListTile<ThemeMode>(
|
||||||
title: const Text('Light'),
|
title: Text(l10n.themeLight),
|
||||||
value: ThemeMode.light,
|
value: ThemeMode.light,
|
||||||
groupValue: ThemeController.to.themeMode,
|
groupValue: ThemeController.to.themeMode,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
|
|
@ -853,7 +931,7 @@ class SettingsPage extends StatelessWidget {
|
||||||
activeColor: scheme.primary,
|
activeColor: scheme.primary,
|
||||||
),
|
),
|
||||||
RadioListTile<ThemeMode>(
|
RadioListTile<ThemeMode>(
|
||||||
title: const Text('Dark'),
|
title: Text(l10n.themeDark),
|
||||||
value: ThemeMode.dark,
|
value: ThemeMode.dark,
|
||||||
groupValue: ThemeController.to.themeMode,
|
groupValue: ThemeController.to.themeMode,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
|
|
@ -863,7 +941,7 @@ class SettingsPage extends StatelessWidget {
|
||||||
activeColor: scheme.primary,
|
activeColor: scheme.primary,
|
||||||
),
|
),
|
||||||
RadioListTile<ThemeMode>(
|
RadioListTile<ThemeMode>(
|
||||||
title: const Text('System Default'),
|
title: Text(l10n.themeSystem),
|
||||||
value: ThemeMode.system,
|
value: ThemeMode.system,
|
||||||
groupValue: ThemeController.to.themeMode,
|
groupValue: ThemeController.to.themeMode,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
|
|
@ -878,32 +956,31 @@ class SettingsPage extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showLogoutDialog(BuildContext context) {
|
void _showLogoutDialog(BuildContext context, AppLocalizations l10n) {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => AlertDialog(
|
builder: (context) => AlertDialog(
|
||||||
title: const Text('Logout'),
|
title: Text(l10n.logoutConfirmTitle),
|
||||||
content: const Text('Are you sure you want to logout?'),
|
content: Text(l10n.logoutConfirmMessage),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
child: const Text('Cancel'),
|
child: Text(l10n.cancel),
|
||||||
),
|
),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
AuthService.to.logout();
|
AuthService.to.logout();
|
||||||
SnackbarUtil.showSuccess('Logged out successfully');
|
SnackbarUtil.showSuccess(l10n.loggedOutSuccess);
|
||||||
},
|
},
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Theme.of(context).colorScheme.error,
|
backgroundColor: Theme.of(context).colorScheme.error,
|
||||||
foregroundColor: Theme.of(context).colorScheme.onError,
|
foregroundColor: Theme.of(context).colorScheme.onError,
|
||||||
),
|
),
|
||||||
child: const Text('Logout'),
|
child: Text(l10n.logout),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,16 +11,18 @@ import 'import_existing_group_dialog.dart';
|
||||||
import 'member_selection_dialog.dart';
|
import 'member_selection_dialog.dart';
|
||||||
import 'group_details_page.dart';
|
import 'group_details_page.dart';
|
||||||
import 'combined_draw_dialog.dart';
|
import 'combined_draw_dialog.dart';
|
||||||
|
import '../../l10n/l10n_x.dart';
|
||||||
|
|
||||||
class ChitGroupsPage extends StatelessWidget {
|
class ChitGroupsPage extends StatelessWidget {
|
||||||
const ChitGroupsPage({super.key});
|
const ChitGroupsPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final l = context.l10n;
|
||||||
final scheme = Theme.of(context).colorScheme;
|
final scheme = Theme.of(context).colorScheme;
|
||||||
|
|
||||||
return AppScaffold(
|
return AppScaffold(
|
||||||
title: 'My Chitfunds',
|
title: l.pageMyChitfunds,
|
||||||
actions: [
|
actions: [
|
||||||
PopupMenuButton<String>(
|
PopupMenuButton<String>(
|
||||||
icon: Icon(Icons.add, size: 24.w),
|
icon: Icon(Icons.add, size: 24.w),
|
||||||
|
|
@ -38,7 +40,7 @@ class ChitGroupsPage extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.add_circle, color: scheme.primary, size: 20.w),
|
Icon(Icons.add_circle, color: scheme.primary, size: 20.w),
|
||||||
SizedBox(width: 12.w),
|
SizedBox(width: 12.w),
|
||||||
const Text('Create New Group'),
|
Text(l.createNewGroupMenu),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -48,7 +50,7 @@ class ChitGroupsPage extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.upload, color: scheme.secondary, size: 20.w),
|
Icon(Icons.upload, color: scheme.secondary, size: 20.w),
|
||||||
SizedBox(width: 12.w),
|
SizedBox(width: 12.w),
|
||||||
const Text('Import Existing Group'),
|
Text(l.importExistingGroupMenu),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -62,8 +64,6 @@ class ChitGroupsPage extends StatelessWidget {
|
||||||
isLoading: service.isLoading.value,
|
isLoading: service.isLoading.value,
|
||||||
isEmpty: service.chitGroups.isEmpty,
|
isEmpty: service.chitGroups.isEmpty,
|
||||||
emptyType: EmptyStateType.noGroups,
|
emptyType: EmptyStateType.noGroups,
|
||||||
emptyTitle: 'No chit groups yet',
|
|
||||||
emptyMessage: 'Create a new chit group or import an existing one.',
|
|
||||||
onRetry: () => service.loadManagerChitGroups(),
|
onRetry: () => service.loadManagerChitGroups(),
|
||||||
child: RefreshIndicator(
|
child: RefreshIndicator(
|
||||||
onRefresh: () => service.loadManagerChitGroups(),
|
onRefresh: () => service.loadManagerChitGroups(),
|
||||||
|
|
|
||||||
|
|
@ -19,12 +19,15 @@ import 'import_existing_group_dialog.dart';
|
||||||
import 'members_page.dart';
|
import 'members_page.dart';
|
||||||
import '../../test_animated_draw.dart';
|
import '../../test_animated_draw.dart';
|
||||||
import '../../features/recordings/recordings_page.dart';
|
import '../../features/recordings/recordings_page.dart';
|
||||||
|
import '../../l10n/app_localizations.dart';
|
||||||
|
import '../../l10n/l10n_x.dart';
|
||||||
|
|
||||||
class ManagerDashboard extends StatelessWidget {
|
class ManagerDashboard extends StatelessWidget {
|
||||||
const ManagerDashboard({super.key});
|
const ManagerDashboard({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final l = context.l10n;
|
||||||
final scheme = Theme.of(context).colorScheme;
|
final scheme = Theme.of(context).colorScheme;
|
||||||
// Initialize services
|
// Initialize services
|
||||||
Get.put(ChitGroupService());
|
Get.put(ChitGroupService());
|
||||||
|
|
@ -40,7 +43,7 @@ class ManagerDashboard extends StatelessWidget {
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text('Dashboard', style: AppText.title(context)),
|
title: Text(l.dashboardTitle, style: AppText.title(context)),
|
||||||
actions: [
|
actions: [
|
||||||
// Notifications with badge
|
// Notifications with badge
|
||||||
Obx(() {
|
Obx(() {
|
||||||
|
|
@ -51,13 +54,13 @@ class ManagerDashboard extends StatelessWidget {
|
||||||
child: Icon(Icons.notifications_rounded, size: 24.w),
|
child: Icon(Icons.notifications_rounded, size: 24.w),
|
||||||
),
|
),
|
||||||
onPressed: () => Get.to(() => const NotificationCenterPage()),
|
onPressed: () => Get.to(() => const NotificationCenterPage()),
|
||||||
tooltip: 'Notifications',
|
tooltip: l.notificationsTooltip,
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(Icons.videocam, size: 24.w),
|
icon: Icon(Icons.videocam, size: 24.w),
|
||||||
onPressed: () => Get.to(() => const RecordingsPage()),
|
onPressed: () => Get.to(() => const RecordingsPage()),
|
||||||
tooltip: 'View Draw Recordings',
|
tooltip: l.recordingsTooltip,
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(Icons.logout, size: 24.w),
|
icon: Icon(Icons.logout, size: 24.w),
|
||||||
|
|
@ -81,7 +84,7 @@ class ManagerDashboard extends StatelessWidget {
|
||||||
backgroundColor: scheme.tertiary,
|
backgroundColor: scheme.tertiary,
|
||||||
foregroundColor: scheme.onTertiary,
|
foregroundColor: scheme.onTertiary,
|
||||||
child: const Icon(Icons.casino),
|
child: const Icon(Icons.casino),
|
||||||
tooltip: 'Test Animated Draw',
|
tooltip: l.testDrawTooltip,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -94,8 +97,6 @@ class ManagerDashboard extends StatelessWidget {
|
||||||
isLoading: service.isLoading.value,
|
isLoading: service.isLoading.value,
|
||||||
isEmpty: service.chitGroups.isEmpty,
|
isEmpty: service.chitGroups.isEmpty,
|
||||||
emptyType: EmptyStateType.noGroups,
|
emptyType: EmptyStateType.noGroups,
|
||||||
emptyTitle: 'No chit groups yet',
|
|
||||||
emptyMessage: 'Create your first group to get started.',
|
|
||||||
onRetry: () => service.loadManagerChitGroups(),
|
onRetry: () => service.loadManagerChitGroups(),
|
||||||
loading: const SkeletonDashboard(),
|
loading: const SkeletonDashboard(),
|
||||||
child: RefreshIndicator(
|
child: RefreshIndicator(
|
||||||
|
|
@ -109,9 +110,9 @@ class ManagerDashboard extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
_buildWelcomeSection(context),
|
_buildWelcomeSection(context),
|
||||||
SizedBox(height: 24.h),
|
SizedBox(height: 24.h),
|
||||||
_buildRecentActivitiesSection(),
|
_buildRecentActivitiesSection(context),
|
||||||
SizedBox(height: 24.h),
|
SizedBox(height: 24.h),
|
||||||
_buildQuickActionsSection(),
|
_buildQuickActionsSection(context),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -142,7 +143,7 @@ class ManagerDashboard extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
_buildWelcomeSection(context),
|
_buildWelcomeSection(context),
|
||||||
SizedBox(height: 24.h),
|
SizedBox(height: 24.h),
|
||||||
_buildDesktopActivitiesAndActions(),
|
_buildDesktopActivitiesAndActions(context),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -176,7 +177,7 @@ class ManagerDashboard extends StatelessWidget {
|
||||||
),
|
),
|
||||||
SizedBox(height: 12.h),
|
SizedBox(height: 12.h),
|
||||||
Obx(() => Text(
|
Obx(() => Text(
|
||||||
AuthService.to.currentUser.value?.fullName ?? 'Manager',
|
AuthService.to.currentUser.value?.fullName ?? context.l10n.managerFallbackName,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16.sp,
|
fontSize: 16.sp,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
|
|
@ -188,7 +189,7 @@ class ManagerDashboard extends StatelessWidget {
|
||||||
)),
|
)),
|
||||||
SizedBox(height: 4.h),
|
SizedBox(height: 4.h),
|
||||||
Text(
|
Text(
|
||||||
'Chit Fund Manager',
|
context.l10n.chitFundManagerRole,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14.sp,
|
fontSize: 14.sp,
|
||||||
color: scheme.onSurfaceVariant,
|
color: scheme.onSurfaceVariant,
|
||||||
|
|
@ -206,38 +207,38 @@ class ManagerDashboard extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
_buildMenuItem(
|
_buildMenuItem(
|
||||||
icon: Icons.dashboard,
|
icon: Icons.dashboard,
|
||||||
title: 'Dashboard',
|
title: context.l10n.menuDashboard,
|
||||||
isSelected: true,
|
isSelected: true,
|
||||||
onTap: () {},
|
onTap: () {},
|
||||||
),
|
),
|
||||||
_buildMenuItem(
|
_buildMenuItem(
|
||||||
icon: Icons.group,
|
icon: Icons.group,
|
||||||
title: 'My Chitfunds',
|
title: context.l10n.menuMyChitfunds,
|
||||||
onTap: () => Get.to(() => const ChitGroupsPage()),
|
onTap: () => Get.to(() => const ChitGroupsPage()),
|
||||||
),
|
),
|
||||||
_buildMenuItem(
|
_buildMenuItem(
|
||||||
icon: Icons.people,
|
icon: Icons.people,
|
||||||
title: 'Members',
|
title: context.l10n.menuMembers,
|
||||||
onTap: () {},
|
onTap: () {},
|
||||||
),
|
),
|
||||||
_buildMenuItem(
|
_buildMenuItem(
|
||||||
icon: Icons.payment,
|
icon: Icons.payment,
|
||||||
title: 'Payments',
|
title: context.l10n.menuPayments,
|
||||||
onTap: () {},
|
onTap: () {},
|
||||||
),
|
),
|
||||||
_buildMenuItem(
|
_buildMenuItem(
|
||||||
icon: Icons.casino,
|
icon: Icons.casino,
|
||||||
title: 'Lottery Draws',
|
title: context.l10n.menuLotteryDraws,
|
||||||
onTap: () {},
|
onTap: () {},
|
||||||
),
|
),
|
||||||
_buildMenuItem(
|
_buildMenuItem(
|
||||||
icon: Icons.analytics,
|
icon: Icons.analytics,
|
||||||
title: 'Reports',
|
title: context.l10n.menuReports,
|
||||||
onTap: () {},
|
onTap: () {},
|
||||||
),
|
),
|
||||||
_buildMenuItem(
|
_buildMenuItem(
|
||||||
icon: Icons.settings,
|
icon: Icons.settings,
|
||||||
title: 'Settings',
|
title: context.l10n.settingsTitle,
|
||||||
onTap: () => Get.to(() => const SettingsPage()),
|
onTap: () => Get.to(() => const SettingsPage()),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
@ -277,16 +278,17 @@ class ManagerDashboard extends StatelessWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildWelcomeSection(BuildContext context) {
|
Widget _buildWelcomeSection(BuildContext context) {
|
||||||
|
final l = context.l10n;
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Welcome back!',
|
l.welcomeBackTitle,
|
||||||
style: AppText.headline(context),
|
style: AppText.headline(context),
|
||||||
),
|
),
|
||||||
SizedBox(height: 8.h),
|
SizedBox(height: 8.h),
|
||||||
Text(
|
Text(
|
||||||
'Here\'s what\'s happening with your chit funds today.',
|
l.welcomeBackSubtitle,
|
||||||
style: AppText.bodyMuted(context),
|
style: AppText.bodyMuted(context),
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
|
|
@ -305,7 +307,8 @@ class ManagerDashboard extends StatelessWidget {
|
||||||
return SizedBox.shrink();
|
return SizedBox.shrink();
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildQuickActionsSection() {
|
Widget _buildQuickActionsSection(BuildContext context) {
|
||||||
|
final l = context.l10n;
|
||||||
return Card(
|
return Card(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.all(20.w),
|
padding: EdgeInsets.all(20.w),
|
||||||
|
|
@ -313,7 +316,7 @@ class ManagerDashboard extends StatelessWidget {
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Quick Actions',
|
l.quickActionsTitle,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 18.sp,
|
fontSize: 18.sp,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
|
|
@ -323,36 +326,36 @@ class ManagerDashboard extends StatelessWidget {
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
QuickActionCard(
|
QuickActionCard(
|
||||||
title: 'Create New Chitfund',
|
title: l.qaCreateChitfundTitle,
|
||||||
subtitle: 'Start a new chit fund group',
|
subtitle: l.qaCreateChitfundSubtitle,
|
||||||
icon: Icons.group_add,
|
icon: Icons.group_add,
|
||||||
color: Colors.green.shade600,
|
color: Colors.green.shade600,
|
||||||
onTap: () => _showCreateGroupDialog(Get.context!),
|
onTap: () => _showCreateGroupDialog(context),
|
||||||
),
|
),
|
||||||
QuickActionCard(
|
QuickActionCard(
|
||||||
title: 'Import Existing Chitfund',
|
title: l.qaImportChitfundTitle,
|
||||||
subtitle: 'Add a group that already started',
|
subtitle: l.qaImportChitfundSubtitle,
|
||||||
icon: Icons.upload,
|
icon: Icons.upload,
|
||||||
color: Colors.blue.shade600,
|
color: Colors.blue.shade600,
|
||||||
onTap: () => _showImportGroupDialog(Get.context!),
|
onTap: () => _showImportGroupDialog(context),
|
||||||
),
|
),
|
||||||
QuickActionCard(
|
QuickActionCard(
|
||||||
title: 'View All Chitfunds',
|
title: l.qaViewAllChitfundsTitle,
|
||||||
subtitle: 'Manage your existing groups',
|
subtitle: l.qaViewAllChitfundsSubtitle,
|
||||||
icon: Icons.list,
|
icon: Icons.list,
|
||||||
color: Colors.teal.shade600,
|
color: Colors.teal.shade600,
|
||||||
onTap: () => _navigateToGroups(),
|
onTap: () => _navigateToGroups(),
|
||||||
),
|
),
|
||||||
QuickActionCard(
|
QuickActionCard(
|
||||||
title: 'Manage Members',
|
title: l.qaManageMembersTitle,
|
||||||
subtitle: 'Add or remove members',
|
subtitle: l.qaManageMembersSubtitle,
|
||||||
icon: Icons.people,
|
icon: Icons.people,
|
||||||
color: Colors.orange.shade600,
|
color: Colors.orange.shade600,
|
||||||
onTap: () => _navigateToMembers(),
|
onTap: () => _navigateToMembers(),
|
||||||
),
|
),
|
||||||
QuickActionCard(
|
QuickActionCard(
|
||||||
title: 'Payment Records',
|
title: l.qaPaymentRecordsTitle,
|
||||||
subtitle: 'Track all transactions',
|
subtitle: l.qaPaymentRecordsSubtitle,
|
||||||
icon: Icons.payment,
|
icon: Icons.payment,
|
||||||
color: Colors.purple.shade600,
|
color: Colors.purple.shade600,
|
||||||
onTap: () => _navigateToPayments(),
|
onTap: () => _navigateToPayments(),
|
||||||
|
|
@ -365,7 +368,8 @@ class ManagerDashboard extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildRecentActivitiesSection() {
|
Widget _buildRecentActivitiesSection(BuildContext context) {
|
||||||
|
final l = context.l10n;
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
|
|
@ -373,7 +377,7 @@ class ManagerDashboard extends StatelessWidget {
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'My Chitfunds',
|
l.sectionMyChitfunds,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 18.sp,
|
fontSize: 18.sp,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
|
|
@ -382,7 +386,7 @@ class ManagerDashboard extends StatelessWidget {
|
||||||
TextButton.icon(
|
TextButton.icon(
|
||||||
onPressed: _navigateToGroups,
|
onPressed: _navigateToGroups,
|
||||||
icon: Icon(Icons.arrow_forward, size: 18.w),
|
icon: Icon(Icons.arrow_forward, size: 18.w),
|
||||||
label: Text('View All', style: TextStyle(fontSize: 14.sp)),
|
label: Text(l.viewAll, style: TextStyle(fontSize: 14.sp)),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
@ -395,7 +399,7 @@ class ManagerDashboard extends StatelessWidget {
|
||||||
padding: EdgeInsets.all(32.w),
|
padding: EdgeInsets.all(32.w),
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
'No chit funds yet',
|
l.noChitFundsYetShort,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14.sp,
|
fontSize: 14.sp,
|
||||||
color: Colors.grey.shade600,
|
color: Colors.grey.shade600,
|
||||||
|
|
@ -408,7 +412,7 @@ class ManagerDashboard extends StatelessWidget {
|
||||||
return Column(
|
return Column(
|
||||||
children: groups.map((group) => Padding(
|
children: groups.map((group) => Padding(
|
||||||
padding: EdgeInsets.only(bottom: 12.h),
|
padding: EdgeInsets.only(bottom: 12.h),
|
||||||
child: _buildGroupQuickCard(group),
|
child: _buildGroupQuickCard(context, group),
|
||||||
)).toList(),
|
)).toList(),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
|
|
@ -416,7 +420,8 @@ class ManagerDashboard extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildGroupQuickCard(dynamic group) {
|
Widget _buildGroupQuickCard(BuildContext context, dynamic group) {
|
||||||
|
final l = context.l10n;
|
||||||
final status = group.status ?? 'forming';
|
final status = group.status ?? 'forming';
|
||||||
final statusColor = _getStatusColor(status);
|
final statusColor = _getStatusColor(status);
|
||||||
|
|
||||||
|
|
@ -447,7 +452,7 @@ class ManagerDashboard extends StatelessWidget {
|
||||||
border: Border.all(color: statusColor, width: 1.5),
|
border: Border.all(color: statusColor, width: 1.5),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
_getStatusText(status),
|
_getStatusText(l, status),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12.sp,
|
fontSize: 12.sp,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
|
|
@ -492,7 +497,7 @@ class ManagerDashboard extends StatelessWidget {
|
||||||
Get.to(() => const ChitGroupsPage());
|
Get.to(() => const ChitGroupsPage());
|
||||||
},
|
},
|
||||||
icon: Icon(Icons.payment, size: 18.w),
|
icon: Icon(Icons.payment, size: 18.w),
|
||||||
label: Text('Record', style: TextStyle(fontSize: 13.sp)),
|
label: Text(l.actionRecord, style: TextStyle(fontSize: 13.sp)),
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Colors.green.shade600,
|
backgroundColor: Colors.green.shade600,
|
||||||
foregroundColor: Colors.white,
|
foregroundColor: Colors.white,
|
||||||
|
|
@ -508,7 +513,7 @@ class ManagerDashboard extends StatelessWidget {
|
||||||
Get.to(() => const ChitGroupsPage());
|
Get.to(() => const ChitGroupsPage());
|
||||||
},
|
},
|
||||||
icon: Icon(Icons.casino, size: 18.w),
|
icon: Icon(Icons.casino, size: 18.w),
|
||||||
label: Text('Draw', style: TextStyle(fontSize: 13.sp)),
|
label: Text(l.actionDraw, style: TextStyle(fontSize: 13.sp)),
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Colors.purple.shade600,
|
backgroundColor: Colors.purple.shade600,
|
||||||
foregroundColor: Colors.white,
|
foregroundColor: Colors.white,
|
||||||
|
|
@ -526,7 +531,7 @@ class ManagerDashboard extends StatelessWidget {
|
||||||
padding: EdgeInsets.symmetric(vertical: 10.h),
|
padding: EdgeInsets.symmetric(vertical: 10.h),
|
||||||
side: BorderSide(color: Colors.grey.shade400),
|
side: BorderSide(color: Colors.grey.shade400),
|
||||||
),
|
),
|
||||||
child: Text('View', style: TextStyle(fontSize: 13.sp)),
|
child: Text(l.actionView, style: TextStyle(fontSize: 13.sp)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
@ -540,7 +545,7 @@ class ManagerDashboard extends StatelessWidget {
|
||||||
Get.to(() => const ChitGroupsPage());
|
Get.to(() => const ChitGroupsPage());
|
||||||
},
|
},
|
||||||
icon: Icon(Icons.arrow_forward, size: 18.w),
|
icon: Icon(Icons.arrow_forward, size: 18.w),
|
||||||
label: Text('Manage Group', style: TextStyle(fontSize: 14.sp)),
|
label: Text(l.actionManageGroup, style: TextStyle(fontSize: 14.sp)),
|
||||||
style: OutlinedButton.styleFrom(
|
style: OutlinedButton.styleFrom(
|
||||||
padding: EdgeInsets.symmetric(vertical: 12.h),
|
padding: EdgeInsets.symmetric(vertical: 12.h),
|
||||||
),
|
),
|
||||||
|
|
@ -583,14 +588,14 @@ class ManagerDashboard extends StatelessWidget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String _getStatusText(String status) {
|
String _getStatusText(AppLocalizations l, String status) {
|
||||||
switch (status.toLowerCase()) {
|
switch (status.toLowerCase()) {
|
||||||
case 'active':
|
case 'active':
|
||||||
return 'Active';
|
return l.groupStatusActive;
|
||||||
case 'forming':
|
case 'forming':
|
||||||
return 'Forming';
|
return l.groupStatusForming;
|
||||||
case 'completed':
|
case 'completed':
|
||||||
return 'Completed';
|
return l.groupStatusCompleted;
|
||||||
default:
|
default:
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
@ -656,16 +661,16 @@ class ManagerDashboard extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildDesktopActivitiesAndActions() {
|
Widget _buildDesktopActivitiesAndActions(BuildContext context) {
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
// My Chitfunds (full width on desktop)
|
// My Chitfunds (full width on desktop)
|
||||||
_buildRecentActivitiesSection(),
|
_buildRecentActivitiesSection(context),
|
||||||
SizedBox(height: 24.h),
|
SizedBox(height: 24.h),
|
||||||
|
|
||||||
// Quick Actions (below chitfunds)
|
// Quick Actions (below chitfunds)
|
||||||
_buildQuickActionsSection(),
|
_buildQuickActionsSection(context),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -674,27 +679,30 @@ class ManagerDashboard extends StatelessWidget {
|
||||||
void _showLogoutDialog(BuildContext context) {
|
void _showLogoutDialog(BuildContext context) {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => AlertDialog(
|
builder: (dialogContext) {
|
||||||
title: const Text('Logout'),
|
final l = dialogContext.l10n;
|
||||||
content: const Text('Are you sure you want to logout?'),
|
return AlertDialog(
|
||||||
actions: [
|
title: Text(l.logoutConfirmTitle),
|
||||||
TextButton(
|
content: Text(l.logoutConfirmMessage),
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
actions: [
|
||||||
child: const Text('Cancel'),
|
TextButton(
|
||||||
),
|
onPressed: () => Navigator.of(dialogContext).pop(),
|
||||||
ElevatedButton(
|
child: Text(l.cancel),
|
||||||
onPressed: () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
AuthService.to.logout();
|
|
||||||
},
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
backgroundColor: Colors.red,
|
|
||||||
foregroundColor: Colors.white,
|
|
||||||
),
|
),
|
||||||
child: const Text('Logout'),
|
ElevatedButton(
|
||||||
),
|
onPressed: () {
|
||||||
],
|
Navigator.of(dialogContext).pop();
|
||||||
),
|
AuthService.to.logout();
|
||||||
|
},
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
foregroundColor: Colors.white,
|
||||||
|
),
|
||||||
|
child: Text(l.logout),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -712,8 +720,8 @@ class ManagerDashboard extends StatelessWidget {
|
||||||
// Reload groups after successful import
|
// Reload groups after successful import
|
||||||
ChitGroupService.to.loadManagerChitGroups();
|
ChitGroupService.to.loadManagerChitGroups();
|
||||||
SnackbarUtil.showSuccess(
|
SnackbarUtil.showSuccess(
|
||||||
'Group imported! Now add members and backfill past data.',
|
L10nSvc.of().groupImportedMessage,
|
||||||
title: 'Success',
|
title: L10nSvc.of().groupImportedTitle,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -729,8 +737,8 @@ class ManagerDashboard extends StatelessWidget {
|
||||||
|
|
||||||
void _navigateToPayments() {
|
void _navigateToPayments() {
|
||||||
SnackbarUtil.showInfo(
|
SnackbarUtil.showInfo(
|
||||||
'Payments page will be implemented next',
|
L10nSvc.of().paymentsPageComingSoon,
|
||||||
title: 'Coming Soon',
|
title: L10nSvc.of().comingSoonTitle,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ import '../../shared/widgets/notification_badge.dart';
|
||||||
import '../../features/notifications/notification_center_page.dart';
|
import '../../features/notifications/notification_center_page.dart';
|
||||||
import 'member_group_details_page.dart';
|
import 'member_group_details_page.dart';
|
||||||
import 'member_payment_dialog.dart';
|
import 'member_payment_dialog.dart';
|
||||||
|
import '../../l10n/app_localizations.dart';
|
||||||
|
import '../../l10n/l10n_x.dart';
|
||||||
|
|
||||||
class MemberDashboard extends StatefulWidget {
|
class MemberDashboard extends StatefulWidget {
|
||||||
const MemberDashboard({super.key});
|
const MemberDashboard({super.key});
|
||||||
|
|
@ -38,12 +40,13 @@ class _MemberDashboardState extends State<MemberDashboard> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final l = context.l10n;
|
||||||
final scheme = Theme.of(context).colorScheme;
|
final scheme = Theme.of(context).colorScheme;
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: scheme.surface,
|
backgroundColor: scheme.surface,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(
|
title: Text(
|
||||||
'My Chitfunds',
|
l.pageMyChitfunds,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 18.sp,
|
fontSize: 18.sp,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
|
|
@ -63,7 +66,7 @@ class _MemberDashboardState extends State<MemberDashboard> {
|
||||||
child: Icon(Icons.notifications_rounded, size: 24.w),
|
child: Icon(Icons.notifications_rounded, size: 24.w),
|
||||||
),
|
),
|
||||||
onPressed: () => Get.to(() => const NotificationCenterPage()),
|
onPressed: () => Get.to(() => const NotificationCenterPage()),
|
||||||
tooltip: 'Notifications',
|
tooltip: l.notificationsTooltip,
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
IconButton(
|
IconButton(
|
||||||
|
|
@ -116,7 +119,9 @@ class _MemberDashboardState extends State<MemberDashboard> {
|
||||||
SizedBox(width: 12.w),
|
SizedBox(width: 12.w),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
'Welcome, ${AuthService.to.currentUser.value?.fullName ?? 'Member'}!',
|
l.memberWelcomeGreeting(
|
||||||
|
AuthService.to.currentUser.value?.fullName ?? l.memberFallbackName,
|
||||||
|
),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 20.sp,
|
fontSize: 20.sp,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
|
|
@ -128,9 +133,7 @@ class _MemberDashboardState extends State<MemberDashboard> {
|
||||||
),
|
),
|
||||||
SizedBox(height: 12.h),
|
SizedBox(height: 12.h),
|
||||||
Text(
|
Text(
|
||||||
groups.isEmpty
|
groups.isEmpty ? l.memberSubtitleEmpty : l.memberSubtitleHasGroups,
|
||||||
? 'Join a chit fund to start managing your investments.'
|
|
||||||
: 'Manage your chit fund investments and track your payments.',
|
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16.sp,
|
fontSize: 16.sp,
|
||||||
color: scheme.onPrimaryContainer.withOpacity(0.92),
|
color: scheme.onPrimaryContainer.withOpacity(0.92),
|
||||||
|
|
@ -157,7 +160,7 @@ class _MemberDashboardState extends State<MemberDashboard> {
|
||||||
|
|
||||||
if (!isLoading && groups.isNotEmpty) ...[
|
if (!isLoading && groups.isNotEmpty) ...[
|
||||||
Text(
|
Text(
|
||||||
'My Chitfunds',
|
l.sectionMyChitfunds,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 20.sp,
|
fontSize: 20.sp,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
|
|
@ -187,31 +190,31 @@ class _MemberDashboardState extends State<MemberDashboard> {
|
||||||
unselectedLabelStyle: TextStyle(fontSize: 12.sp),
|
unselectedLabelStyle: TextStyle(fontSize: 12.sp),
|
||||||
iconSize: 24.w,
|
iconSize: 24.w,
|
||||||
items: [
|
items: [
|
||||||
const BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
icon: Icon(Icons.home),
|
icon: const Icon(Icons.home),
|
||||||
label: 'Home',
|
label: l.navHome,
|
||||||
),
|
),
|
||||||
const BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
icon: Icon(Icons.payment),
|
icon: const Icon(Icons.payment),
|
||||||
label: 'Payments',
|
label: l.navPayments,
|
||||||
),
|
),
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
icon: NotificationBadge(
|
icon: NotificationBadge(
|
||||||
count: unreadCount,
|
count: unreadCount,
|
||||||
child: const Icon(Icons.notifications),
|
child: const Icon(Icons.notifications),
|
||||||
),
|
),
|
||||||
label: 'Notifications',
|
label: l.navNotifications,
|
||||||
),
|
),
|
||||||
const BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
icon: Icon(Icons.person),
|
icon: const Icon(Icons.person),
|
||||||
label: 'Profile',
|
label: l.navProfile,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
onTap: (index) {
|
onTap: (index) {
|
||||||
if (index == 2) {
|
if (index == 2) {
|
||||||
Get.to(() => const NotificationCenterPage());
|
Get.to(() => const NotificationCenterPage());
|
||||||
} else {
|
} else {
|
||||||
SnackbarUtil.showInfo('Feature coming soon');
|
SnackbarUtil.showInfo(l.featureComingSoonMessage);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -220,6 +223,7 @@ class _MemberDashboardState extends State<MemberDashboard> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildEmptyState(BuildContext context) {
|
Widget _buildEmptyState(BuildContext context) {
|
||||||
|
final l = context.l10n;
|
||||||
final scheme = Theme.of(context).colorScheme;
|
final scheme = Theme.of(context).colorScheme;
|
||||||
return Center(
|
return Center(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
|
|
@ -234,7 +238,7 @@ class _MemberDashboardState extends State<MemberDashboard> {
|
||||||
),
|
),
|
||||||
SizedBox(height: 24.h),
|
SizedBox(height: 24.h),
|
||||||
Text(
|
Text(
|
||||||
'No Chit Funds Yet',
|
l.memberEmptyChitTitle,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 22.sp,
|
fontSize: 22.sp,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
|
|
@ -243,7 +247,7 @@ class _MemberDashboardState extends State<MemberDashboard> {
|
||||||
),
|
),
|
||||||
SizedBox(height: 12.h),
|
SizedBox(height: 12.h),
|
||||||
Text(
|
Text(
|
||||||
'You haven\'t joined any chit funds yet.\nContact your manager to get started!',
|
l.memberEmptyChitBody,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16.sp,
|
fontSize: 16.sp,
|
||||||
|
|
@ -270,7 +274,7 @@ class _MemberDashboardState extends State<MemberDashboard> {
|
||||||
),
|
),
|
||||||
SizedBox(width: 8.w),
|
SizedBox(width: 8.w),
|
||||||
Text(
|
Text(
|
||||||
'How to get started?',
|
l.memberHowToStartTitle,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16.sp,
|
fontSize: 16.sp,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
|
|
@ -281,9 +285,7 @@ class _MemberDashboardState extends State<MemberDashboard> {
|
||||||
),
|
),
|
||||||
SizedBox(height: 12.h),
|
SizedBox(height: 12.h),
|
||||||
Text(
|
Text(
|
||||||
'1. Your manager will add you to a chit group\n'
|
l.memberHowToStartBody,
|
||||||
'2. You\'ll receive a notification\n'
|
|
||||||
'3. Start managing your payments here!',
|
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14.sp,
|
fontSize: 14.sp,
|
||||||
color: scheme.onSurfaceVariant,
|
color: scheme.onSurfaceVariant,
|
||||||
|
|
@ -300,9 +302,10 @@ class _MemberDashboardState extends State<MemberDashboard> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildGroupCard(BuildContext context, dynamic group) {
|
Widget _buildGroupCard(BuildContext context, dynamic group) {
|
||||||
|
final l = context.l10n;
|
||||||
final scheme = Theme.of(context).colorScheme;
|
final scheme = Theme.of(context).colorScheme;
|
||||||
final color = scheme.primary;
|
final color = scheme.primary;
|
||||||
final groupName = group.name ?? 'Unnamed Group';
|
final groupName = group.name ?? l.unnamedGroupLong;
|
||||||
final totalValue = group.totalValue ?? 0.0;
|
final totalValue = group.totalValue ?? 0.0;
|
||||||
final monthlyInstallment = group.monthlyInstallment ?? 0.0;
|
final monthlyInstallment = group.monthlyInstallment ?? 0.0;
|
||||||
final durationMonths = group.durationMonths ?? 0;
|
final durationMonths = group.durationMonths ?? 0;
|
||||||
|
|
@ -343,7 +346,7 @@ class _MemberDashboardState extends State<MemberDashboard> {
|
||||||
border: Border.all(color: _getStatusColor(context, status), width: 1.5),
|
border: Border.all(color: _getStatusColor(context, status), width: 1.5),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
_getStatusText(status),
|
_memberStatusLabel(l, status),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14.sp,
|
fontSize: 14.sp,
|
||||||
color: _getStatusColor(context, status),
|
color: _getStatusColor(context, status),
|
||||||
|
|
@ -359,11 +362,15 @@ class _MemberDashboardState extends State<MemberDashboard> {
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildGroupInfo(context, 'Total Value', totalValueFormatted),
|
child: _buildGroupInfo(context, l.labelTotalValue, totalValueFormatted),
|
||||||
),
|
),
|
||||||
SizedBox(width: 8.w),
|
SizedBox(width: 8.w),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildGroupInfo(context, 'Duration', '$durationMonths months'),
|
child: _buildGroupInfo(
|
||||||
|
context,
|
||||||
|
l.labelDuration,
|
||||||
|
'$durationMonths ${l.monthsSuffix}',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
@ -371,11 +378,11 @@ class _MemberDashboardState extends State<MemberDashboard> {
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildGroupInfo(context, 'Installment', installmentValueFormatted),
|
child: _buildGroupInfo(context, l.labelInstallment, installmentValueFormatted),
|
||||||
),
|
),
|
||||||
SizedBox(width: 8.w),
|
SizedBox(width: 8.w),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildGroupInfo(context, 'Status', _getStatusText(status)),
|
child: _buildGroupInfo(context, l.labelStatus, _memberStatusLabel(l, status)),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
@ -393,7 +400,7 @@ class _MemberDashboardState extends State<MemberDashboard> {
|
||||||
onPressed: () => _showPaymentDialog(group),
|
onPressed: () => _showPaymentDialog(group),
|
||||||
icon: Icon(Icons.payment, size: 20.w),
|
icon: Icon(Icons.payment, size: 20.w),
|
||||||
label: Text(
|
label: Text(
|
||||||
'Pay Now',
|
l.payNowButton,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 15.sp,
|
fontSize: 15.sp,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
|
|
@ -424,7 +431,7 @@ class _MemberDashboardState extends State<MemberDashboard> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
'Details',
|
l.detailsButton,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 15.sp,
|
fontSize: 15.sp,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
|
|
@ -449,7 +456,7 @@ class _MemberDashboardState extends State<MemberDashboard> {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (myMember == null) {
|
if (myMember == null) {
|
||||||
SnackbarUtil.showError('Member information not found');
|
SnackbarUtil.showError(context.l10n.memberInfoNotFound);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -481,8 +488,19 @@ class _MemberDashboardState extends State<MemberDashboard> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String _getStatusText(String status) {
|
String _memberStatusLabel(AppLocalizations l, String status) {
|
||||||
return status[0].toUpperCase() + status.substring(1).toLowerCase();
|
switch (status.toLowerCase()) {
|
||||||
|
case 'active':
|
||||||
|
return l.groupStatusActive;
|
||||||
|
case 'pending':
|
||||||
|
case 'forming':
|
||||||
|
return l.groupStatusPending;
|
||||||
|
case 'completed':
|
||||||
|
return l.groupStatusCompleted;
|
||||||
|
default:
|
||||||
|
if (status.isEmpty) return status;
|
||||||
|
return status[0].toUpperCase() + status.substring(1).toLowerCase();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String _formatCurrency(double amount) {
|
String _formatCurrency(double amount) {
|
||||||
|
|
@ -532,27 +550,30 @@ class _MemberDashboardState extends State<MemberDashboard> {
|
||||||
void _showLogoutDialog(BuildContext context) {
|
void _showLogoutDialog(BuildContext context) {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => AlertDialog(
|
builder: (dialogContext) {
|
||||||
title: const Text('Logout'),
|
final l = dialogContext.l10n;
|
||||||
content: const Text('Are you sure you want to logout?'),
|
return AlertDialog(
|
||||||
actions: [
|
title: Text(l.logoutConfirmTitle),
|
||||||
TextButton(
|
content: Text(l.logoutConfirmMessage),
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
actions: [
|
||||||
child: const Text('Cancel'),
|
TextButton(
|
||||||
),
|
onPressed: () => Navigator.of(dialogContext).pop(),
|
||||||
ElevatedButton(
|
child: Text(l.cancel),
|
||||||
onPressed: () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
AuthService.to.logout();
|
|
||||||
},
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
backgroundColor: Theme.of(context).colorScheme.error,
|
|
||||||
foregroundColor: Theme.of(context).colorScheme.onError,
|
|
||||||
),
|
),
|
||||||
child: const Text('Logout'),
|
ElevatedButton(
|
||||||
),
|
onPressed: () {
|
||||||
],
|
Navigator.of(dialogContext).pop();
|
||||||
),
|
AuthService.to.logout();
|
||||||
|
},
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: Theme.of(dialogContext).colorScheme.error,
|
||||||
|
foregroundColor: Theme.of(dialogContext).colorScheme.onError,
|
||||||
|
),
|
||||||
|
child: Text(l.logout),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
{
|
||||||
|
"@@locale": "en",
|
||||||
|
"appTitle": "LuckyChit",
|
||||||
|
"settingsTitle": "Settings",
|
||||||
|
"sectionAppearance": "Appearance",
|
||||||
|
"sectionLanguage": "Language",
|
||||||
|
"sectionAccount": "Account",
|
||||||
|
"sectionPaymentSettings": "Payment Settings",
|
||||||
|
"sectionNotifications": "Notifications",
|
||||||
|
"sectionAbout": "About",
|
||||||
|
"languageTitle": "App language",
|
||||||
|
"languageSubtitle": "English or Telugu",
|
||||||
|
"languageEnglish": "English",
|
||||||
|
"languageTelugu": "Telugu (తెలుగు)",
|
||||||
|
"chooseLanguageTitle": "Choose language",
|
||||||
|
"themeTitle": "Theme",
|
||||||
|
"themeLight": "Light",
|
||||||
|
"themeDark": "Dark",
|
||||||
|
"themeSystem": "System default",
|
||||||
|
"chooseThemeTitle": "Choose theme",
|
||||||
|
"darkModeTitle": "Dark mode",
|
||||||
|
"darkModeSubtitle": "Override system settings",
|
||||||
|
"changePasswordTitle": "Change password",
|
||||||
|
"changePasswordSubtitle": "Update your password",
|
||||||
|
"pushNotificationsTitle": "Push notifications",
|
||||||
|
"pushNotificationsSubtitle": "Receive push notifications",
|
||||||
|
"paymentRemindersTitle": "Payment reminders",
|
||||||
|
"paymentRemindersSubtitle": "Reminders for upcoming payments",
|
||||||
|
"drawNotificationsTitle": "Draw notifications",
|
||||||
|
"drawNotificationsSubtitle": "Alerts for lottery draws",
|
||||||
|
"upiIdTitle": "UPI ID",
|
||||||
|
"loading": "Loading…",
|
||||||
|
"active": "Active",
|
||||||
|
"notConfigured": "Not configured",
|
||||||
|
"configureBackend": "Configure in backend/.env",
|
||||||
|
"copyUpiIdTooltip": "Copy UPI ID",
|
||||||
|
"upiCopiedClipboard": "UPI ID copied to clipboard",
|
||||||
|
"paymentStatisticsTitle": "Payment statistics",
|
||||||
|
"paymentStatisticsSubtitle": "View payment insights",
|
||||||
|
"transactionFeesTitle": "Transaction fees",
|
||||||
|
"transactionFeesSubtitle": "0% fees • Save lakhs per year!",
|
||||||
|
"free": "FREE",
|
||||||
|
"appVersionTitle": "App version",
|
||||||
|
"privacyPolicyTitle": "Privacy policy",
|
||||||
|
"termsOfServiceTitle": "Terms of service",
|
||||||
|
"logout": "Logout",
|
||||||
|
"logoutConfirmTitle": "Logout",
|
||||||
|
"logoutConfirmMessage": "Are you sure you want to logout?",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"close": "Close",
|
||||||
|
"copied": "Copied!",
|
||||||
|
"profileComingSoon": "Profile page coming soon",
|
||||||
|
"changePasswordComingSoon": "Change password feature coming soon",
|
||||||
|
"notificationComingSoon": "Notification settings coming soon",
|
||||||
|
"paymentStatsComingSoon": "Payment statistics coming soon",
|
||||||
|
"privacyComingSoon": "Privacy policy page coming soon",
|
||||||
|
"termsComingSoon": "Terms of service page coming soon",
|
||||||
|
"loggedOutSuccess": "Logged out successfully",
|
||||||
|
"upiPaymentSettingsTitle": "UPI payment settings",
|
||||||
|
"currentUpiId": "Current UPI ID",
|
||||||
|
"upiNotConfiguredMessage": "UPI ID not configured. Update backend/.env file.",
|
||||||
|
"howToUpdateUpi": "How to update UPI ID",
|
||||||
|
"stepOpenEnv": "Open backend/.env file",
|
||||||
|
"stepUpdatePhonepe": "Update PHONEPE_UPI_ID=your_upi@paytm",
|
||||||
|
"stepRestartBackend": "Restart backend server",
|
||||||
|
"stepRefreshScreen": "Refresh this screen",
|
||||||
|
"proTipTitle": "Pro tip",
|
||||||
|
"proTipBody": "Members can pay using ANY UPI app (PhonePe, GPay, Paytm) directly to your personal UPI ID with 0% transaction fees!"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,694 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||||
|
import 'package:intl/intl.dart' as intl;
|
||||||
|
|
||||||
|
import 'app_localizations_en.dart';
|
||||||
|
import 'app_localizations_te.dart';
|
||||||
|
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
|
||||||
|
/// Callers can lookup localized strings with an instance of AppLocalizations
|
||||||
|
/// returned by `AppLocalizations.of(context)`.
|
||||||
|
///
|
||||||
|
/// Applications need to include `AppLocalizations.delegate()` in their app's
|
||||||
|
/// `localizationDelegates` list, and the locales they support in the app's
|
||||||
|
/// `supportedLocales` list. For example:
|
||||||
|
///
|
||||||
|
/// ```dart
|
||||||
|
/// import 'l10n/app_localizations.dart';
|
||||||
|
///
|
||||||
|
/// return MaterialApp(
|
||||||
|
/// localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||||
|
/// supportedLocales: AppLocalizations.supportedLocales,
|
||||||
|
/// home: MyApplicationHome(),
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ## Update pubspec.yaml
|
||||||
|
///
|
||||||
|
/// Please make sure to update your pubspec.yaml to include the following
|
||||||
|
/// packages:
|
||||||
|
///
|
||||||
|
/// ```yaml
|
||||||
|
/// dependencies:
|
||||||
|
/// # Internationalization support.
|
||||||
|
/// flutter_localizations:
|
||||||
|
/// sdk: flutter
|
||||||
|
/// intl: any # Use the pinned version from flutter_localizations
|
||||||
|
///
|
||||||
|
/// # Rest of dependencies
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ## iOS Applications
|
||||||
|
///
|
||||||
|
/// iOS applications define key application metadata, including supported
|
||||||
|
/// locales, in an Info.plist file that is built into the application bundle.
|
||||||
|
/// To configure the locales supported by your app, you’ll need to edit this
|
||||||
|
/// file.
|
||||||
|
///
|
||||||
|
/// First, open your project’s ios/Runner.xcworkspace Xcode workspace file.
|
||||||
|
/// Then, in the Project Navigator, open the Info.plist file under the Runner
|
||||||
|
/// project’s Runner folder.
|
||||||
|
///
|
||||||
|
/// Next, select the Information Property List item, select Add Item from the
|
||||||
|
/// Editor menu, then select Localizations from the pop-up menu.
|
||||||
|
///
|
||||||
|
/// Select and expand the newly-created Localizations item then, for each
|
||||||
|
/// locale your application supports, add a new item and select the locale
|
||||||
|
/// you wish to add from the pop-up menu in the Value field. This list should
|
||||||
|
/// be consistent with the languages listed in the AppLocalizations.supportedLocales
|
||||||
|
/// property.
|
||||||
|
abstract class AppLocalizations {
|
||||||
|
AppLocalizations(String locale) : localeName = intl.Intl.canonicalizedLocale(locale.toString());
|
||||||
|
|
||||||
|
final String localeName;
|
||||||
|
|
||||||
|
static AppLocalizations? of(BuildContext context) {
|
||||||
|
return Localizations.of<AppLocalizations>(context, AppLocalizations);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const LocalizationsDelegate<AppLocalizations> delegate = _AppLocalizationsDelegate();
|
||||||
|
|
||||||
|
/// A list of this localizations delegate along with the default localizations
|
||||||
|
/// delegates.
|
||||||
|
///
|
||||||
|
/// Returns a list of localizations delegates containing this delegate along with
|
||||||
|
/// GlobalMaterialLocalizations.delegate, GlobalCupertinoLocalizations.delegate,
|
||||||
|
/// and GlobalWidgetsLocalizations.delegate.
|
||||||
|
///
|
||||||
|
/// Additional delegates can be added by appending to this list in
|
||||||
|
/// MaterialApp. This list does not have to be used at all if a custom list
|
||||||
|
/// of delegates is preferred or required.
|
||||||
|
static const List<LocalizationsDelegate<dynamic>> localizationsDelegates = <LocalizationsDelegate<dynamic>>[
|
||||||
|
delegate,
|
||||||
|
GlobalMaterialLocalizations.delegate,
|
||||||
|
GlobalCupertinoLocalizations.delegate,
|
||||||
|
GlobalWidgetsLocalizations.delegate,
|
||||||
|
];
|
||||||
|
|
||||||
|
/// A list of this localizations delegate's supported locales.
|
||||||
|
static const List<Locale> supportedLocales = <Locale>[
|
||||||
|
Locale('en'),
|
||||||
|
Locale('te')
|
||||||
|
];
|
||||||
|
|
||||||
|
/// No description provided for @appTitle.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'LuckyChit'**
|
||||||
|
String get appTitle;
|
||||||
|
|
||||||
|
/// No description provided for @settingsTitle.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Settings'**
|
||||||
|
String get settingsTitle;
|
||||||
|
|
||||||
|
/// No description provided for @sectionAppearance.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Appearance'**
|
||||||
|
String get sectionAppearance;
|
||||||
|
|
||||||
|
/// No description provided for @sectionLanguage.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Language'**
|
||||||
|
String get sectionLanguage;
|
||||||
|
|
||||||
|
/// No description provided for @sectionAccount.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Account'**
|
||||||
|
String get sectionAccount;
|
||||||
|
|
||||||
|
/// No description provided for @sectionPaymentSettings.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Payment Settings'**
|
||||||
|
String get sectionPaymentSettings;
|
||||||
|
|
||||||
|
/// No description provided for @sectionNotifications.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Notifications'**
|
||||||
|
String get sectionNotifications;
|
||||||
|
|
||||||
|
/// No description provided for @sectionAbout.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'About'**
|
||||||
|
String get sectionAbout;
|
||||||
|
|
||||||
|
/// No description provided for @languageTitle.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'App language'**
|
||||||
|
String get languageTitle;
|
||||||
|
|
||||||
|
/// No description provided for @languageSubtitle.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'English or Telugu'**
|
||||||
|
String get languageSubtitle;
|
||||||
|
|
||||||
|
/// No description provided for @languageEnglish.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'English'**
|
||||||
|
String get languageEnglish;
|
||||||
|
|
||||||
|
/// No description provided for @languageTelugu.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Telugu (తెలుగు)'**
|
||||||
|
String get languageTelugu;
|
||||||
|
|
||||||
|
/// No description provided for @chooseLanguageTitle.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Choose language'**
|
||||||
|
String get chooseLanguageTitle;
|
||||||
|
|
||||||
|
/// No description provided for @themeTitle.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Theme'**
|
||||||
|
String get themeTitle;
|
||||||
|
|
||||||
|
/// No description provided for @themeLight.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Light'**
|
||||||
|
String get themeLight;
|
||||||
|
|
||||||
|
/// No description provided for @themeDark.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Dark'**
|
||||||
|
String get themeDark;
|
||||||
|
|
||||||
|
/// No description provided for @themeSystem.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'System default'**
|
||||||
|
String get themeSystem;
|
||||||
|
|
||||||
|
/// No description provided for @chooseThemeTitle.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Choose theme'**
|
||||||
|
String get chooseThemeTitle;
|
||||||
|
|
||||||
|
/// No description provided for @darkModeTitle.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Dark mode'**
|
||||||
|
String get darkModeTitle;
|
||||||
|
|
||||||
|
/// No description provided for @darkModeSubtitle.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Override system settings'**
|
||||||
|
String get darkModeSubtitle;
|
||||||
|
|
||||||
|
/// No description provided for @changePasswordTitle.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Change password'**
|
||||||
|
String get changePasswordTitle;
|
||||||
|
|
||||||
|
/// No description provided for @changePasswordSubtitle.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Update your password'**
|
||||||
|
String get changePasswordSubtitle;
|
||||||
|
|
||||||
|
/// No description provided for @pushNotificationsTitle.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Push notifications'**
|
||||||
|
String get pushNotificationsTitle;
|
||||||
|
|
||||||
|
/// No description provided for @pushNotificationsSubtitle.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Receive push notifications'**
|
||||||
|
String get pushNotificationsSubtitle;
|
||||||
|
|
||||||
|
/// No description provided for @paymentRemindersTitle.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Payment reminders'**
|
||||||
|
String get paymentRemindersTitle;
|
||||||
|
|
||||||
|
/// No description provided for @paymentRemindersSubtitle.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Reminders for upcoming payments'**
|
||||||
|
String get paymentRemindersSubtitle;
|
||||||
|
|
||||||
|
/// No description provided for @drawNotificationsTitle.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Draw notifications'**
|
||||||
|
String get drawNotificationsTitle;
|
||||||
|
|
||||||
|
/// No description provided for @drawNotificationsSubtitle.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Alerts for lottery draws'**
|
||||||
|
String get drawNotificationsSubtitle;
|
||||||
|
|
||||||
|
/// No description provided for @upiIdTitle.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'UPI ID'**
|
||||||
|
String get upiIdTitle;
|
||||||
|
|
||||||
|
/// No description provided for @loading.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Loading…'**
|
||||||
|
String get loading;
|
||||||
|
|
||||||
|
/// No description provided for @active.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Active'**
|
||||||
|
String get active;
|
||||||
|
|
||||||
|
/// No description provided for @notConfigured.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Not configured'**
|
||||||
|
String get notConfigured;
|
||||||
|
|
||||||
|
/// No description provided for @configureBackend.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Configure in backend/.env'**
|
||||||
|
String get configureBackend;
|
||||||
|
|
||||||
|
/// No description provided for @copyUpiIdTooltip.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Copy UPI ID'**
|
||||||
|
String get copyUpiIdTooltip;
|
||||||
|
|
||||||
|
/// No description provided for @upiCopiedClipboard.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'UPI ID copied to clipboard'**
|
||||||
|
String get upiCopiedClipboard;
|
||||||
|
|
||||||
|
/// No description provided for @paymentStatisticsTitle.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Payment statistics'**
|
||||||
|
String get paymentStatisticsTitle;
|
||||||
|
|
||||||
|
/// No description provided for @paymentStatisticsSubtitle.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'View payment insights'**
|
||||||
|
String get paymentStatisticsSubtitle;
|
||||||
|
|
||||||
|
/// No description provided for @transactionFeesTitle.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Transaction fees'**
|
||||||
|
String get transactionFeesTitle;
|
||||||
|
|
||||||
|
/// No description provided for @transactionFeesSubtitle.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'0% fees • Save lakhs per year!'**
|
||||||
|
String get transactionFeesSubtitle;
|
||||||
|
|
||||||
|
/// No description provided for @free.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'FREE'**
|
||||||
|
String get free;
|
||||||
|
|
||||||
|
/// No description provided for @appVersionTitle.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'App version'**
|
||||||
|
String get appVersionTitle;
|
||||||
|
|
||||||
|
/// No description provided for @privacyPolicyTitle.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Privacy policy'**
|
||||||
|
String get privacyPolicyTitle;
|
||||||
|
|
||||||
|
/// No description provided for @termsOfServiceTitle.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Terms of service'**
|
||||||
|
String get termsOfServiceTitle;
|
||||||
|
|
||||||
|
/// No description provided for @logout.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Logout'**
|
||||||
|
String get logout;
|
||||||
|
|
||||||
|
/// No description provided for @logoutConfirmTitle.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Logout'**
|
||||||
|
String get logoutConfirmTitle;
|
||||||
|
|
||||||
|
/// No description provided for @logoutConfirmMessage.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Are you sure you want to logout?'**
|
||||||
|
String get logoutConfirmMessage;
|
||||||
|
|
||||||
|
/// No description provided for @cancel.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Cancel'**
|
||||||
|
String get cancel;
|
||||||
|
|
||||||
|
/// No description provided for @close.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Close'**
|
||||||
|
String get close;
|
||||||
|
|
||||||
|
/// No description provided for @copied.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Copied!'**
|
||||||
|
String get copied;
|
||||||
|
|
||||||
|
/// No description provided for @profileComingSoon.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Profile page coming soon'**
|
||||||
|
String get profileComingSoon;
|
||||||
|
|
||||||
|
/// No description provided for @changePasswordComingSoon.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Change password feature coming soon'**
|
||||||
|
String get changePasswordComingSoon;
|
||||||
|
|
||||||
|
/// No description provided for @notificationComingSoon.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Notification settings coming soon'**
|
||||||
|
String get notificationComingSoon;
|
||||||
|
|
||||||
|
/// No description provided for @paymentStatsComingSoon.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Payment statistics coming soon'**
|
||||||
|
String get paymentStatsComingSoon;
|
||||||
|
|
||||||
|
/// No description provided for @privacyComingSoon.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Privacy policy page coming soon'**
|
||||||
|
String get privacyComingSoon;
|
||||||
|
|
||||||
|
/// No description provided for @termsComingSoon.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Terms of service page coming soon'**
|
||||||
|
String get termsComingSoon;
|
||||||
|
|
||||||
|
/// No description provided for @loggedOutSuccess.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Logged out successfully'**
|
||||||
|
String get loggedOutSuccess;
|
||||||
|
|
||||||
|
/// No description provided for @upiPaymentSettingsTitle.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'UPI payment settings'**
|
||||||
|
String get upiPaymentSettingsTitle;
|
||||||
|
|
||||||
|
/// No description provided for @currentUpiId.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Current UPI ID'**
|
||||||
|
String get currentUpiId;
|
||||||
|
|
||||||
|
/// No description provided for @upiNotConfiguredMessage.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'UPI ID not configured. Update backend/.env file.'**
|
||||||
|
String get upiNotConfiguredMessage;
|
||||||
|
|
||||||
|
/// No description provided for @howToUpdateUpi.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'How to update UPI ID'**
|
||||||
|
String get howToUpdateUpi;
|
||||||
|
|
||||||
|
/// No description provided for @stepOpenEnv.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Open backend/.env file'**
|
||||||
|
String get stepOpenEnv;
|
||||||
|
|
||||||
|
/// No description provided for @stepUpdatePhonepe.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Update PHONEPE_UPI_ID=your_upi@paytm'**
|
||||||
|
String get stepUpdatePhonepe;
|
||||||
|
|
||||||
|
/// No description provided for @stepRestartBackend.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Restart backend server'**
|
||||||
|
String get stepRestartBackend;
|
||||||
|
|
||||||
|
/// No description provided for @stepRefreshScreen.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Refresh this screen'**
|
||||||
|
String get stepRefreshScreen;
|
||||||
|
|
||||||
|
/// No description provided for @proTipTitle.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Pro tip'**
|
||||||
|
String get proTipTitle;
|
||||||
|
|
||||||
|
/// No description provided for @proTipBody.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Members can pay using ANY UPI app (PhonePe, GPay, Paytm) directly to your personal UPI ID with 0% transaction fees!'**
|
||||||
|
String get proTipBody;
|
||||||
|
|
||||||
|
String get ok;
|
||||||
|
String get save;
|
||||||
|
String get retry;
|
||||||
|
String get delete;
|
||||||
|
String get userLabel;
|
||||||
|
String get managerFallbackName;
|
||||||
|
|
||||||
|
String get snackTitleError;
|
||||||
|
String get snackTitleSuccess;
|
||||||
|
String get operationFailedShort;
|
||||||
|
|
||||||
|
String get failedLoadChitGroups;
|
||||||
|
String get chitfundCreatedSuccess;
|
||||||
|
String get failedCreateChitGroup;
|
||||||
|
String get failedUpdateChitGroup;
|
||||||
|
String get chitGroupDeletedSuccess;
|
||||||
|
String get failedDeleteChitGroup;
|
||||||
|
String get failedLoadGroupDetails;
|
||||||
|
String get failedLoadGroupMembers;
|
||||||
|
String get memberAddedSuccess;
|
||||||
|
String get failedAddMember;
|
||||||
|
String get memberRemovedSuccess;
|
||||||
|
String get failedRemoveMember;
|
||||||
|
String get memberStatusUpdatedSuccess;
|
||||||
|
String get failedUpdateMemberStatus;
|
||||||
|
String get failedLoadPayments;
|
||||||
|
String get paymentRecordedSuccess;
|
||||||
|
String get failedRecordPayment;
|
||||||
|
String get failedLoadGroupStatistics;
|
||||||
|
String get chitfundStartedSuccess;
|
||||||
|
String get failedStartChitGroup;
|
||||||
|
String get failedLoadMonthlyDraws;
|
||||||
|
String get failedCreateMonthlyDraw;
|
||||||
|
String get failedLoadDrawStatistics;
|
||||||
|
String get failedLoadFinancialData;
|
||||||
|
|
||||||
|
String get signupFailedTitle;
|
||||||
|
String get signupFailedGeneric;
|
||||||
|
String get loginFailedTitle;
|
||||||
|
String get loginFailedGeneric;
|
||||||
|
String get passwordChangedSuccess;
|
||||||
|
String get failedChangePassword;
|
||||||
|
|
||||||
|
String get stateSomethingWentWrong;
|
||||||
|
|
||||||
|
String get emptyNoGroupsTitle;
|
||||||
|
String get emptyNoGroupsMessage;
|
||||||
|
String get emptyNoGroupsAction;
|
||||||
|
String get emptyNoMembersTitle;
|
||||||
|
String get emptyNoMembersMessage;
|
||||||
|
String get emptyNoMembersAction;
|
||||||
|
String get emptyNoPaymentsTitle;
|
||||||
|
String get emptyNoPaymentsMessage;
|
||||||
|
String get emptyNoPaymentsAction;
|
||||||
|
String get emptyNoActivitiesTitle;
|
||||||
|
String get emptyNoActivitiesMessage;
|
||||||
|
String get emptyNoActivitiesAction;
|
||||||
|
String get emptyNoResultsTitle;
|
||||||
|
String get emptyNoResultsMessage;
|
||||||
|
String get emptyNoResultsAction;
|
||||||
|
String get emptyErrorTitle;
|
||||||
|
String get emptyErrorMessage;
|
||||||
|
String get emptyErrorAction;
|
||||||
|
String get emptyNoInternetTitle;
|
||||||
|
String get emptyNoInternetMessage;
|
||||||
|
String get emptyNoInternetAction;
|
||||||
|
|
||||||
|
String get dashboardTitle;
|
||||||
|
String get notificationsTooltip;
|
||||||
|
String get recordingsTooltip;
|
||||||
|
String get testDrawTooltip;
|
||||||
|
String get chitFundManagerRole;
|
||||||
|
String get menuDashboard;
|
||||||
|
String get menuMyChitfunds;
|
||||||
|
String get menuMembers;
|
||||||
|
String get menuPayments;
|
||||||
|
String get menuLotteryDraws;
|
||||||
|
String get menuReports;
|
||||||
|
String get welcomeBackTitle;
|
||||||
|
String get welcomeBackSubtitle;
|
||||||
|
String get quickActionsTitle;
|
||||||
|
String get qaCreateChitfundTitle;
|
||||||
|
String get qaCreateChitfundSubtitle;
|
||||||
|
String get qaImportChitfundTitle;
|
||||||
|
String get qaImportChitfundSubtitle;
|
||||||
|
String get qaViewAllChitfundsTitle;
|
||||||
|
String get qaViewAllChitfundsSubtitle;
|
||||||
|
String get qaManageMembersTitle;
|
||||||
|
String get qaManageMembersSubtitle;
|
||||||
|
String get qaPaymentRecordsTitle;
|
||||||
|
String get qaPaymentRecordsSubtitle;
|
||||||
|
String get sectionMyChitfunds;
|
||||||
|
String get viewAll;
|
||||||
|
String get noChitFundsYetShort;
|
||||||
|
String get groupStatusActive;
|
||||||
|
String get groupStatusForming;
|
||||||
|
String get groupStatusCompleted;
|
||||||
|
String get unnamedGroup;
|
||||||
|
String get actionRecord;
|
||||||
|
String get actionDraw;
|
||||||
|
String get actionView;
|
||||||
|
String get actionManageGroup;
|
||||||
|
String get groupImportedMessage;
|
||||||
|
String get groupImportedTitle;
|
||||||
|
String get paymentsPageComingSoon;
|
||||||
|
String get comingSoonTitle;
|
||||||
|
|
||||||
|
String get pageMyChitfunds;
|
||||||
|
String get createNewGroupMenu;
|
||||||
|
String get importExistingGroupMenu;
|
||||||
|
|
||||||
|
String get appDisplayName;
|
||||||
|
String get authLoginTagline;
|
||||||
|
String get authSignupScreenTitle;
|
||||||
|
String get authSignupTagline;
|
||||||
|
String get labelMobileNumber;
|
||||||
|
String get labelMobileNumberRequired;
|
||||||
|
String get labelPassword;
|
||||||
|
String get labelPasswordRequired;
|
||||||
|
String get labelFullNameRequired;
|
||||||
|
String get labelEmailOptional;
|
||||||
|
String get labelAddressOptional;
|
||||||
|
String get labelEmergencyContactOptional;
|
||||||
|
String get labelConfirmPasswordRequired;
|
||||||
|
String get validatorEnterMobile;
|
||||||
|
String get validatorMobileTenDigits;
|
||||||
|
String get validatorMobileDigitsOnly;
|
||||||
|
String get validatorEnterFullName;
|
||||||
|
String get validatorValidEmail;
|
||||||
|
String get validatorEmergencyTenDigits;
|
||||||
|
String get validatorEmergencyDigitsOnly;
|
||||||
|
String get validatorEnterPasswordAuth;
|
||||||
|
String get validatorPasswordMinSixAuth;
|
||||||
|
String get validatorConfirmPassword;
|
||||||
|
String get validatorPasswordsMismatch;
|
||||||
|
String get tooltipShowPassword;
|
||||||
|
String get tooltipHidePassword;
|
||||||
|
String get signInButton;
|
||||||
|
String get createAccountButton;
|
||||||
|
String get alreadyHaveAccount;
|
||||||
|
String get loginLink;
|
||||||
|
String get loginInvalidCredentials;
|
||||||
|
String get signupSuccessWelcome;
|
||||||
|
String get signupFailedGenericUi;
|
||||||
|
String get featureComingSoonMessage;
|
||||||
|
|
||||||
|
String memberWelcomeGreeting(String name);
|
||||||
|
String get memberFallbackName;
|
||||||
|
String get memberSubtitleEmpty;
|
||||||
|
String get memberSubtitleHasGroups;
|
||||||
|
String get navHome;
|
||||||
|
String get navPayments;
|
||||||
|
String get navNotifications;
|
||||||
|
String get navProfile;
|
||||||
|
String get memberEmptyChitTitle;
|
||||||
|
String get memberEmptyChitBody;
|
||||||
|
String get memberHowToStartTitle;
|
||||||
|
String get memberHowToStartBody;
|
||||||
|
String get unnamedGroupLong;
|
||||||
|
String get labelTotalValue;
|
||||||
|
String get labelDuration;
|
||||||
|
String get monthsSuffix;
|
||||||
|
String get labelInstallment;
|
||||||
|
String get labelStatus;
|
||||||
|
String get groupStatusPending;
|
||||||
|
String get payNowButton;
|
||||||
|
String get detailsButton;
|
||||||
|
String get memberInfoNotFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
|
||||||
|
const _AppLocalizationsDelegate();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<AppLocalizations> load(Locale locale) {
|
||||||
|
return SynchronousFuture<AppLocalizations>(lookupAppLocalizations(locale));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool isSupported(Locale locale) => <String>['en', 'te'].contains(locale.languageCode);
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool shouldReload(_AppLocalizationsDelegate old) => false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AppLocalizations lookupAppLocalizations(Locale locale) {
|
||||||
|
|
||||||
|
|
||||||
|
// Lookup logic when only language code is specified.
|
||||||
|
switch (locale.languageCode) {
|
||||||
|
case 'en': return AppLocalizationsEn();
|
||||||
|
case 'te': return AppLocalizationsTe();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw FlutterError(
|
||||||
|
'AppLocalizations.delegate failed to load unsupported locale "$locale". This is likely '
|
||||||
|
'an issue with the localizations generation tool. Please file an issue '
|
||||||
|
'on GitHub with a reproducible sample app and the gen-l10n configuration '
|
||||||
|
'that was used.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,706 @@
|
||||||
|
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 => 'LuckyChit';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get settingsTitle => 'Settings';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get sectionAppearance => 'Appearance';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get sectionLanguage => 'Language';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get sectionAccount => 'Account';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get sectionPaymentSettings => 'Payment Settings';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get sectionNotifications => 'Notifications';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get sectionAbout => 'About';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get languageTitle => 'App language';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get languageSubtitle => 'English or Telugu';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get languageEnglish => 'English';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get languageTelugu => 'Telugu (తెలుగు)';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get chooseLanguageTitle => 'Choose language';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get themeTitle => 'Theme';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get themeLight => 'Light';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get themeDark => 'Dark';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get themeSystem => 'System default';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get chooseThemeTitle => 'Choose theme';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get darkModeTitle => 'Dark mode';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get darkModeSubtitle => 'Override system settings';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get changePasswordTitle => 'Change password';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get changePasswordSubtitle => 'Update your password';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get pushNotificationsTitle => 'Push notifications';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get pushNotificationsSubtitle => 'Receive push notifications';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get paymentRemindersTitle => 'Payment reminders';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get paymentRemindersSubtitle => 'Reminders for upcoming payments';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get drawNotificationsTitle => 'Draw notifications';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get drawNotificationsSubtitle => 'Alerts for lottery draws';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get upiIdTitle => 'UPI ID';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get loading => 'Loading…';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get active => 'Active';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get notConfigured => 'Not configured';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get configureBackend => 'Configure in backend/.env';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get copyUpiIdTooltip => 'Copy UPI ID';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get upiCopiedClipboard => 'UPI ID copied to clipboard';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get paymentStatisticsTitle => 'Payment statistics';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get paymentStatisticsSubtitle => 'View payment insights';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get transactionFeesTitle => 'Transaction fees';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get transactionFeesSubtitle => '0% fees • Save lakhs per year!';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get free => 'FREE';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get appVersionTitle => 'App version';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get privacyPolicyTitle => 'Privacy policy';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get termsOfServiceTitle => 'Terms of service';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get logout => 'Logout';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get logoutConfirmTitle => 'Logout';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get logoutConfirmMessage => 'Are you sure you want to logout?';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get cancel => 'Cancel';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get close => 'Close';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get copied => 'Copied!';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get profileComingSoon => 'Profile page coming soon';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get changePasswordComingSoon => 'Change password feature coming soon';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get notificationComingSoon => 'Notification settings coming soon';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get paymentStatsComingSoon => 'Payment statistics coming soon';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get privacyComingSoon => 'Privacy policy page coming soon';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get termsComingSoon => 'Terms of service page coming soon';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get loggedOutSuccess => 'Logged out successfully';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get upiPaymentSettingsTitle => 'UPI payment settings';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get currentUpiId => 'Current UPI ID';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get upiNotConfiguredMessage => 'UPI ID not configured. Update backend/.env file.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get howToUpdateUpi => 'How to update UPI ID';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get stepOpenEnv => 'Open backend/.env file';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get stepUpdatePhonepe => 'Update PHONEPE_UPI_ID=your_upi@paytm';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get stepRestartBackend => 'Restart backend server';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get stepRefreshScreen => 'Refresh this screen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get proTipTitle => 'Pro tip';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get proTipBody => 'Members can pay using ANY UPI app (PhonePe, GPay, Paytm) directly to your personal UPI ID with 0% transaction fees!';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get ok => 'OK';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get save => 'Save';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get retry => 'Retry';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get delete => 'Delete';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get userLabel => 'User';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get managerFallbackName => 'Manager';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get snackTitleError => 'Error';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get snackTitleSuccess => 'Success';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get operationFailedShort => 'Failed';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedLoadChitGroups => 'Failed to load chit groups';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get chitfundCreatedSuccess => 'Chitfund created successfully';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedCreateChitGroup => 'Failed to create chit group';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedUpdateChitGroup => 'Failed to update chit group';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get chitGroupDeletedSuccess => 'Chit group deleted successfully';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedDeleteChitGroup => 'Failed to delete chit group';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedLoadGroupDetails => 'Failed to load group details';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedLoadGroupMembers => 'Failed to load group members';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get memberAddedSuccess => 'Member added successfully';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedAddMember => 'Failed to add member';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get memberRemovedSuccess => 'Member removed successfully';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedRemoveMember => 'Failed to remove member';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get memberStatusUpdatedSuccess => 'Member status updated successfully';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedUpdateMemberStatus => 'Failed to update member status';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedLoadPayments => 'Failed to load payments';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get paymentRecordedSuccess => 'Payment recorded successfully';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedRecordPayment => 'Failed to record payment';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedLoadGroupStatistics => 'Failed to load group statistics';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get chitfundStartedSuccess => 'Chitfund started successfully';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedStartChitGroup => 'Failed to start chit group';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedLoadMonthlyDraws => 'Failed to load monthly draws';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedCreateMonthlyDraw => 'Failed to create monthly draw';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedLoadDrawStatistics => 'Failed to load draw statistics';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedLoadFinancialData => 'Failed to load financial data';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get signupFailedTitle => 'Signup Failed';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get signupFailedGeneric => 'Signup failed. Please try again.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get loginFailedTitle => 'Login Failed';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get loginFailedGeneric => 'Login failed. Please try again.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get passwordChangedSuccess => 'Password changed successfully';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedChangePassword => 'Failed to change password';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get stateSomethingWentWrong => 'Something went wrong';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyNoGroupsTitle => 'No Chit Groups Yet';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyNoGroupsMessage =>
|
||||||
|
'You haven\'t created any chit groups yet.\nCreate your first group or import an existing one!';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyNoGroupsAction => 'Create Group';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyNoMembersTitle => 'No Members Yet';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyNoMembersMessage =>
|
||||||
|
'This group doesn\'t have any members yet.\nAdd members to get started!';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyNoMembersAction => 'Add Members';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyNoPaymentsTitle => 'No Payments Yet';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyNoPaymentsMessage =>
|
||||||
|
'No payment records found.\nPayments will appear here once recorded.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyNoPaymentsAction => 'Record Payment';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyNoActivitiesTitle => 'No Recent Activities';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyNoActivitiesMessage =>
|
||||||
|
'Your recent activities will appear here.\nStart using the app to see updates!';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyNoActivitiesAction => 'Refresh';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyNoResultsTitle => 'No Results Found';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyNoResultsMessage =>
|
||||||
|
'We couldn\'t find what you\'re looking for.\nTry adjusting your search or filters.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyNoResultsAction => 'Clear Filters';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyErrorTitle => 'Oops! Something Went Wrong';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyErrorMessage =>
|
||||||
|
'We encountered an error while loading data.\nPlease try again.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyErrorAction => 'Retry';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyNoInternetTitle => 'No Internet Connection';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyNoInternetMessage =>
|
||||||
|
'Please check your internet connection\nand try again.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyNoInternetAction => 'Retry';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get dashboardTitle => 'Dashboard';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get notificationsTooltip => 'Notifications';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get recordingsTooltip => 'View draw recordings';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get testDrawTooltip => 'Test animated draw';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get chitFundManagerRole => 'Chit Fund Manager';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get menuDashboard => 'Dashboard';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get menuMyChitfunds => 'My Chitfunds';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get menuMembers => 'Members';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get menuPayments => 'Payments';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get menuLotteryDraws => 'Lottery Draws';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get menuReports => 'Reports';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get welcomeBackTitle => 'Welcome back!';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get welcomeBackSubtitle =>
|
||||||
|
'Here\'s what\'s happening with your chit funds today.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get quickActionsTitle => 'Quick Actions';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get qaCreateChitfundTitle => 'Create New Chitfund';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get qaCreateChitfundSubtitle => 'Start a new chit fund group';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get qaImportChitfundTitle => 'Import Existing Chitfund';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get qaImportChitfundSubtitle => 'Add a group that already started';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get qaViewAllChitfundsTitle => 'View All Chitfunds';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get qaViewAllChitfundsSubtitle => 'Manage your existing groups';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get qaManageMembersTitle => 'Manage Members';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get qaManageMembersSubtitle => 'Add or remove members';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get qaPaymentRecordsTitle => 'Payment Records';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get qaPaymentRecordsSubtitle => 'Track all transactions';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get sectionMyChitfunds => 'My Chitfunds';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get viewAll => 'View All';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get noChitFundsYetShort => 'No chit funds yet';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get groupStatusActive => 'Active';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get groupStatusForming => 'Forming';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get groupStatusCompleted => 'Completed';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get unnamedGroup => 'Unnamed';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get actionRecord => 'Record';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get actionDraw => 'Draw';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get actionView => 'View';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get actionManageGroup => 'Manage Group';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get groupImportedMessage =>
|
||||||
|
'Group imported! Now add members and backfill past data.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get groupImportedTitle => 'Success';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get paymentsPageComingSoon => 'Payments page will be implemented next';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get comingSoonTitle => 'Coming Soon';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get pageMyChitfunds => 'My Chitfunds';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get createNewGroupMenu => 'Create New Group';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get importExistingGroupMenu => 'Import Existing Group';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get appDisplayName => 'LuckyChit';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get authLoginTagline =>
|
||||||
|
'Chit fund management that feels effortless.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get authSignupScreenTitle => 'Create account';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get authSignupTagline => 'Set up your profile in under a minute.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get labelMobileNumber => 'Mobile number';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get labelMobileNumberRequired => 'Mobile number *';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get labelPassword => 'Password';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get labelPasswordRequired => 'Password *';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get labelFullNameRequired => 'Full name *';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get labelEmailOptional => 'Email (optional)';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get labelAddressOptional => 'Address (optional)';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get labelEmergencyContactOptional => 'Emergency contact (optional)';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get labelConfirmPasswordRequired => 'Confirm password *';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get validatorEnterMobile => 'Please enter mobile number';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get validatorMobileTenDigits => 'Mobile number must be 10 digits';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get validatorMobileDigitsOnly =>
|
||||||
|
'Mobile number must contain only digits';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get validatorEnterFullName => 'Please enter your full name';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get validatorValidEmail => 'Please enter a valid email address';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get validatorEmergencyTenDigits =>
|
||||||
|
'Emergency contact must be 10 digits';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get validatorEmergencyDigitsOnly =>
|
||||||
|
'Emergency contact must contain only digits';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get validatorEnterPasswordAuth => 'Please enter password';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get validatorPasswordMinSixAuth =>
|
||||||
|
'Password must be at least 6 characters';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get validatorConfirmPassword => 'Please confirm password';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get validatorPasswordsMismatch => 'Passwords do not match';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get tooltipShowPassword => 'Show password';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get tooltipHidePassword => 'Hide password';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get signInButton => 'Sign in';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get createAccountButton => 'Create account';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get alreadyHaveAccount => 'Already have an account? ';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get loginLink => 'Login';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get loginInvalidCredentials =>
|
||||||
|
'Invalid mobile number or password. Please try again.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get signupSuccessWelcome =>
|
||||||
|
'Account created successfully! Welcome to LuckyChit.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get signupFailedGenericUi =>
|
||||||
|
'Failed to create account. Please try again.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get featureComingSoonMessage => 'Feature coming soon';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String memberWelcomeGreeting(String name) => 'Welcome, $name!';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get memberFallbackName => 'Member';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get memberSubtitleEmpty =>
|
||||||
|
'Join a chit fund to start managing your investments.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get memberSubtitleHasGroups =>
|
||||||
|
'Manage your chit fund investments and track your payments.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get navHome => 'Home';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get navPayments => 'Payments';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get navNotifications => 'Notifications';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get navProfile => 'Profile';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get memberEmptyChitTitle => 'No Chit Funds Yet';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get memberEmptyChitBody =>
|
||||||
|
'You haven\'t joined any chit funds yet.\nContact your manager to get started!';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get memberHowToStartTitle => 'How to get started?';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get memberHowToStartBody =>
|
||||||
|
'1. Your manager will add you to a chit group\n'
|
||||||
|
'2. You\'ll receive a notification\n'
|
||||||
|
'3. Start managing your payments here!';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get unnamedGroupLong => 'Unnamed Group';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get labelTotalValue => 'Total Value';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get labelDuration => 'Duration';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get monthsSuffix => 'months';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get labelInstallment => 'Installment';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get labelStatus => 'Status';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get groupStatusPending => 'Pending';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get payNowButton => 'Pay Now';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get detailsButton => 'Details';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get memberInfoNotFound => 'Member information not found';
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,714 @@
|
||||||
|
import 'app_localizations.dart';
|
||||||
|
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
|
||||||
|
/// The translations for Telugu (`te`).
|
||||||
|
class AppLocalizationsTe extends AppLocalizations {
|
||||||
|
AppLocalizationsTe([String locale = 'te']) : super(locale);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get appTitle => 'లక్కీచిట్';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get settingsTitle => 'సెట్టింగ్స్';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get sectionAppearance => 'రూపం';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get sectionLanguage => 'భాష';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get sectionAccount => 'ఖాతా';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get sectionPaymentSettings => 'చెల్లింపు సెట్టింగ్స్';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get sectionNotifications => 'నోటిఫికేషన్లు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get sectionAbout => 'గురించి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get languageTitle => 'యాప్ భాష';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get languageSubtitle => 'ఇంగ్లీషు లేదా తెలుగు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get languageEnglish => 'ఇంగ్లీషు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get languageTelugu => 'తెలుగు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get chooseLanguageTitle => 'భాష ఎంచుకోండి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get themeTitle => 'థీమ్';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get themeLight => 'లైట్';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get themeDark => 'డార్క్';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get themeSystem => 'సిస్టమ్ డిఫాల్ట్';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get chooseThemeTitle => 'థీమ్ ఎంచుకోండి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get darkModeTitle => 'డార్క్ మోడ్';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get darkModeSubtitle => 'సిస్టమ్ సెట్టింగ్స్ను ఓవర్రైడ్ చేయండి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get changePasswordTitle => 'పాస్వర్డ్ మార్చండి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get changePasswordSubtitle => 'మీ పాస్వర్డ్ను నవీకరించండి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get pushNotificationsTitle => 'పుష్ నోటిఫికేషన్లు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get pushNotificationsSubtitle => 'పుష్ నోటిఫికేషన్లు అందుకోండి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get paymentRemindersTitle => 'చెల్లింపు రిమైండర్లు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get paymentRemindersSubtitle => 'రాబోయే చెల్లింపుల కోసం రిమైండర్లు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get drawNotificationsTitle => 'డ్రా నోటిఫికేషన్లు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get drawNotificationsSubtitle => 'లాటరీ డ్రాల కోసం అలర్ట్లు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get upiIdTitle => 'UPI ID';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get loading => 'లోడ్ అవుతోంది…';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get active => 'సక్రియం';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get notConfigured => 'కాన్ఫిగర్ చేయలేదు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get configureBackend => 'backend/.env లో కాన్ఫిగర్ చేయండి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get copyUpiIdTooltip => 'UPI ID కాపీ చేయండి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get upiCopiedClipboard => 'UPI ID క్లిప్బోర్డ్కు కాపీ అయింది';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get paymentStatisticsTitle => 'చెల్లింపు గణాంకాలు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get paymentStatisticsSubtitle => 'చెల్లింపు అంతర్దృష్టులను చూడండి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get transactionFeesTitle => 'లావాదేవీ ఫీజులు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get transactionFeesSubtitle => '0% ఫీజులు • సంవత్సరానికి లక్షలు ఆదా!';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get free => 'ఉచితం';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get appVersionTitle => 'యాప్ వెర్షన్';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get privacyPolicyTitle => 'గోప్యతా విధానం';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get termsOfServiceTitle => 'సేవా నిబంధనలు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get logout => 'లాగ్ అవుట్';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get logoutConfirmTitle => 'లాగ్ అవుట్';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get logoutConfirmMessage => 'మీరు ఖచ్చితంగా లాగ్ అవుట్ కావాలనుకుంటున్నారా?';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get cancel => 'రద్దు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get close => 'మూసివేయి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get copied => 'కాపీ అయింది!';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get profileComingSoon => 'ప్రొఫైల్ పేజీ త్వరలో వస్తుంది';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get changePasswordComingSoon => 'పాస్వర్డ్ మార్పు ఫీచర్ త్వరలో వస్తుంది';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get notificationComingSoon => 'నోటిఫికేషన్ సెట్టింగ్స్ త్వరలో వస్తాయి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get paymentStatsComingSoon => 'చెల్లింపు గణాంకాలు త్వరలో వస్తాయి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get privacyComingSoon => 'గోప్యతా విధానం పేజీ త్వరలో వస్తుంది';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get termsComingSoon => 'సేవా నిబంధనల పేజీ త్వరలో వస్తుంది';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get loggedOutSuccess => 'విజయవంతంగా లాగ్ అవుట్ అయ్యారు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get upiPaymentSettingsTitle => 'UPI చెల్లింపు సెట్టింగ్స్';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get currentUpiId => 'ప్రస్తుత UPI ID';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get upiNotConfiguredMessage => 'UPI ID కాన్ఫిగర్ చేయలేదు. backend/.env ఫైల్ను నవీకరించండి.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get howToUpdateUpi => 'UPI ID ఎలా నవీకరించాలి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get stepOpenEnv => 'backend/.env ఫైల్ను తెరవండి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get stepUpdatePhonepe => 'PHONEPE_UPI_ID=your_upi@paytm ను నవీకరించండి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get stepRestartBackend => 'బ్యాకెండ్ సర్వర్ను రీస్టార్ట్ చేయండి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get stepRefreshScreen => 'ఈ స్క్రీన్ను రిఫ్రెష్ చేయండి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get proTipTitle => 'ప్రో టిప్';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get proTipBody => 'సభ్యులు ఏ UPI యాప్తోనైనా (PhonePe, GPay, Paytm) మీ వ్యక్తిగత UPI IDకు నేరుగా 0% లావాదేవీ ఫీజుతో చెల్లించవచ్చు!';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get ok => 'సరే';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get save => 'సేవ్';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get retry => 'మళ్లీ ప్రయత్నించండి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get delete => 'తొలగించు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get userLabel => 'వినియోగదారు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get managerFallbackName => 'మేనేజర్';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get snackTitleError => 'లోపం';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get snackTitleSuccess => 'విజయం';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get operationFailedShort => 'విఫలమైంది';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedLoadChitGroups => 'చిట్ గ్రూప్లను లోడ్ చేయడంలో విఫలమైంది';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get chitfundCreatedSuccess => 'చిట్ఫండ్ విజయవంతంగా సృష్టించబడింది';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedCreateChitGroup => 'చిట్ గ్రూప్ సృష్టించడంలో విఫలమైంది';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedUpdateChitGroup => 'చిట్ గ్రూప్ నవీకరించడంలో విఫలమైంది';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get chitGroupDeletedSuccess => 'చిట్ గ్రూప్ విజయవంతంగా తొలగించబడింది';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedDeleteChitGroup => 'చిట్ గ్రూప్ తొలగించడంలో విఫలమైంది';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedLoadGroupDetails => 'గ్రూప్ వివరాలను లోడ్ చేయడంలో విఫలమైంది';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedLoadGroupMembers => 'గ్రూప్ సభ్యులను లోడ్ చేయడంలో విఫలమైంది';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get memberAddedSuccess => 'సభ్యుడు విజయవంతంగా జోడించబడ్డారు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedAddMember => 'సభ్యుడిని జోడించడంలో విఫలమైంది';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get memberRemovedSuccess => 'సభ్యుడు విజయవంతంగా తొలగించబడ్డారు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedRemoveMember => 'సభ్యుడిని తొలగించడంలో విఫలమైంది';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get memberStatusUpdatedSuccess => 'సభ్య స్థితి విజయవంతంగా నవీకరించబడింది';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedUpdateMemberStatus => 'సభ్య స్థితిని నవీకరించడంలో విఫలమైంది';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedLoadPayments => 'చెల్లింపులను లోడ్ చేయడంలో విఫలమైంది';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get paymentRecordedSuccess => 'చెల్లింపు విజయవంతంగా నమోదు చేయబడింది';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedRecordPayment => 'చెల్లింపు నమోదు చేయడంలో విఫలమైంది';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedLoadGroupStatistics => 'గ్రూప్ గణాంకాలను లోడ్ చేయడంలో విఫలమైంది';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get chitfundStartedSuccess => 'చిట్ఫండ్ విజయవంతంగా ప్రారంభమైంది';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedStartChitGroup => 'చిట్ గ్రూప్ ప్రారంభించడంలో విఫలమైంది';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedLoadMonthlyDraws => 'నెలవారీ డ్రాలను లోడ్ చేయడంలో విఫలమైంది';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedCreateMonthlyDraw => 'నెలవారీ డ్రా సృష్టించడంలో విఫలమైంది';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedLoadDrawStatistics => 'డ్రా గణాంకాలను లోడ్ చేయడంలో విఫలమైంది';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedLoadFinancialData => 'ఆర్థిక డేటాను లోడ్ చేయడంలో విఫలమైంది';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get signupFailedTitle => 'నమోదు విఫలమైంది';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get signupFailedGeneric => 'నమోదు విఫలమైంది. దయచేసి మళ్లీ ప్రయత్నించండి.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get loginFailedTitle => 'లాగిన్ విఫలమైంది';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get loginFailedGeneric => 'లాగిన్ విఫలమైంది. దయచేసి మళ్లీ ప్రయత్నించండి.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get passwordChangedSuccess => 'పాస్వర్డ్ విజయవంతంగా మార్చబడింది';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedChangePassword => 'పాస్వర్డ్ మార్చడంలో విఫలమైంది';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get stateSomethingWentWrong => 'ఏదో తప్పు జరిగింది';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyNoGroupsTitle => 'ఇంకా చిట్ గ్రూప్లు లేవు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyNoGroupsMessage =>
|
||||||
|
'మీరు ఇంకా చిట్ గ్రూప్లు సృష్టించలేదు.\nమొదటి గ్రూప్ సృష్టించండి లేదా ఉన్నదాన్ని దిగుమతి చేయండి!';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyNoGroupsAction => 'గ్రూప్ సృష్టించు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyNoMembersTitle => 'ఇంకా సభ్యులు లేరు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyNoMembersMessage =>
|
||||||
|
'ఈ గ్రూప్కు ఇంకా సభ్యులు లేరు.\nప్రారంభించడానికి సభ్యులను జోడించండి!';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyNoMembersAction => 'సభ్యులను జోడించు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyNoPaymentsTitle => 'ఇంకా చెల్లింపులు లేవు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyNoPaymentsMessage =>
|
||||||
|
'చెల్లింపు రికార్డ్లు కనుగొనబడలేదు.\nనమోదు చేసిన తర్వాత ఇక్కడ కనిపిస్తాయి.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyNoPaymentsAction => 'చెల్లింపు నమోదు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyNoActivitiesTitle => 'ఇటీవలి కార్యకలాపాలు లేవు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyNoActivitiesMessage =>
|
||||||
|
'మీ ఇటీవలి కార్యకలాపాలు ఇక్కడ కనిపిస్తాయి.\nనవీకరణల కోసం యాప్ను ఉపయోగించండి!';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyNoActivitiesAction => 'రిఫ్రెష్';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyNoResultsTitle => 'ఫలితాలు లేవు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyNoResultsMessage =>
|
||||||
|
'మీరు వెతుకుతున్నది కనుగొనలేకపోయాము.\nశోధన లేదా ఫిల్టర్లను మార్చి ప్రయత్నించండి.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyNoResultsAction => 'ఫిల్టర్లు క్లియర్';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyErrorTitle => 'అయ్యో! ఏదో తప్పు జరిగింది';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyErrorMessage =>
|
||||||
|
'డేటా లోడ్ చేస్తూ లోపం వచ్చింది.\nదయచేసి మళ్లీ ప్రయత్నించండి.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyErrorAction => 'మళ్లీ ప్రయత్నించు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyNoInternetTitle => 'ఇంటర్నెట్ కనెక్షన్ లేదు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyNoInternetMessage =>
|
||||||
|
'దయచేసి మీ ఇంటర్నెట్ కనెక్షన్ను తనిఖీ చేసి\nమళ్లీ ప్రయత్నించండి.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get emptyNoInternetAction => 'మళ్లీ ప్రయత్నించు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get dashboardTitle => 'డాష్బోర్డ్';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get notificationsTooltip => 'నోటిఫికేషన్లు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get recordingsTooltip => 'డ్రా రికార్డింగ్లు చూడండి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get testDrawTooltip => 'యానిమేటెడ్ డ్రా పరీక్ష';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get chitFundManagerRole => 'చిట్ ఫండ్ మేనేజర్';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get menuDashboard => 'డాష్బోర్డ్';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get menuMyChitfunds => 'నా చిట్ఫండ్లు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get menuMembers => 'సభ్యులు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get menuPayments => 'చెల్లింపులు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get menuLotteryDraws => 'లాటరీ డ్రాలు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get menuReports => 'నివేదికలు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get welcomeBackTitle => 'మళ్లీ స్వాగతం!';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get welcomeBackSubtitle =>
|
||||||
|
'ఈ రోజు మీ చిట్ ఫండ్లతో ఏమి జరుగుతోందో ఇక్కడ ఉంది.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get quickActionsTitle => 'త్వరిత చర్యలు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get qaCreateChitfundTitle => 'కొత్త చిట్ఫండ్ సృష్టించు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get qaCreateChitfundSubtitle => 'కొత్త చిట్ ఫండ్ గ్రూప్ ప్రారంభించండి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get qaImportChitfundTitle => 'ఉన్న చిట్ఫండ్ దిగుమతి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get qaImportChitfundSubtitle => 'ఇప్పటికే ప్రారంభమైన గ్రూప్ జోడించండి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get qaViewAllChitfundsTitle => 'అన్ని చిట్ఫండ్లు చూడండి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get qaViewAllChitfundsSubtitle => 'మీ గ్రూప్లను నిర్వహించండి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get qaManageMembersTitle => 'సభ్యులను నిర్వహించు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get qaManageMembersSubtitle => 'సభ్యులను జోడించండి లేదా తొలగించండి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get qaPaymentRecordsTitle => 'చెల్లింపు రికార్డ్లు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get qaPaymentRecordsSubtitle => 'అన్ని లావాదేవీలను ట్రాక్ చేయండి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get sectionMyChitfunds => 'నా చిట్ఫండ్లు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get viewAll => 'అన్నీ చూడండి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get noChitFundsYetShort => 'ఇంకా చిట్ ఫండ్లు లేవు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get groupStatusActive => 'సక్రియం';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get groupStatusForming => 'ఏర్పాటులో';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get groupStatusCompleted => 'పూర్తయింది';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get unnamedGroup => 'పేరులేని';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get actionRecord => 'నమోదు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get actionDraw => 'డ్రా';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get actionView => 'చూడండి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get actionManageGroup => 'గ్రూప్ నిర్వహణ';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get groupImportedMessage =>
|
||||||
|
'గ్రూప్ దిగుమతి అయ్యింది! ఇప్పుడు సభ్యులను జోడించి గత డేటా నింపండి.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get groupImportedTitle => 'విజయం';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get paymentsPageComingSoon =>
|
||||||
|
'చెల్లింపుల పేజీ తదుపరి అమలు చేయబడుతుంది';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get comingSoonTitle => 'త్వరలో';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get pageMyChitfunds => 'నా చిట్ఫండ్లు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get createNewGroupMenu => 'కొత్త గ్రూప్ సృష్టించు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get importExistingGroupMenu => 'ఉన్న గ్రూప్ దిగుమతి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get appDisplayName => 'LuckyChit';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get authLoginTagline =>
|
||||||
|
'చిట్ ఫండ్ నిర్వహణ సులభంగా అనిపించేలా.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get authSignupScreenTitle => 'ఖాతా సృష్టించు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get authSignupTagline =>
|
||||||
|
'ఒక నిమిషంలో మీ ప్రొఫైల్ సెటప్ చేయండి.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get labelMobileNumber => 'మొబైల్ నంబర్';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get labelMobileNumberRequired => 'మొబైల్ నంబర్ *';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get labelPassword => 'పాస్వర్డ్';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get labelPasswordRequired => 'పాస్వర్డ్ *';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get labelFullNameRequired => 'పూర్తి పేరు *';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get labelEmailOptional => 'ఇమెయిల్ (ఐచ్ఛికం)';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get labelAddressOptional => 'చిరునామా (ఐచ్ఛికం)';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get labelEmergencyContactOptional =>
|
||||||
|
'అత్యవసర సంప్రదింపు (ఐచ్ఛికం)';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get labelConfirmPasswordRequired => 'పాస్వర్డ్ నిర్ధారించు *';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get validatorEnterMobile => 'దయచేసి మొబైల్ నంబర్ నమోదు చేయండి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get validatorMobileTenDigits =>
|
||||||
|
'మొబైల్ నంబర్ 10 అంకెలు ఉండాలి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get validatorMobileDigitsOnly =>
|
||||||
|
'మొబైల్ నంబర్లో అంకెలు మాత్రమే ఉండాలి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get validatorEnterFullName => 'దయచేసి మీ పూర్తి పేరు నమోదు చేయండి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get validatorValidEmail =>
|
||||||
|
'దయచేసి సరైన ఇమెయిల్ చిరునామా నమోదు చేయండి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get validatorEmergencyTenDigits =>
|
||||||
|
'అత్యవసర సంప్రదింపు 10 అంకెలు ఉండాలి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get validatorEmergencyDigitsOnly =>
|
||||||
|
'అత్యవసర సంప్రదింపులో అంకెలు మాత్రమే ఉండాలి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get validatorEnterPasswordAuth =>
|
||||||
|
'దయచేసి పాస్వర్డ్ నమోదు చేయండి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get validatorPasswordMinSixAuth =>
|
||||||
|
'పాస్వర్డ్ కనీసం 6 అక్షరాలు ఉండాలి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get validatorConfirmPassword =>
|
||||||
|
'దయచేసి పాస్వర్డ్ నిర్ధారించండి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get validatorPasswordsMismatch =>
|
||||||
|
'పాస్వర్డ్లు సరిపోలడం లేదు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get tooltipShowPassword => 'పాస్వర్డ్ చూపు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get tooltipHidePassword => 'పాస్వర్డ్ దాచు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get signInButton => 'సైన్ ఇన్';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get createAccountButton => 'ఖాతా సృష్టించు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get alreadyHaveAccount => 'ఇప్పటికే ఖాతా ఉందా? ';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get loginLink => 'లాగిన్';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get loginInvalidCredentials =>
|
||||||
|
'తప్పు మొబైల్ నంబర్ లేదా పాస్వర్డ్. మళ్లీ ప్రయత్నించండి.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get signupSuccessWelcome =>
|
||||||
|
'ఖాతా విజయవంతంగా సృష్టించబడింది! LuckyChitకు స్వాగతం.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get signupFailedGenericUi =>
|
||||||
|
'ఖాతా సృష్టించడంలో విఫలమైంది. మళ్లీ ప్రయత్నించండి.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get featureComingSoonMessage => 'ఫీచర్ త్వరలో వస్తుంది';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String memberWelcomeGreeting(String name) => 'స్వాగతం, $name!';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get memberFallbackName => 'సభ్యుడు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get memberSubtitleEmpty =>
|
||||||
|
'మీ పెట్టుబడులను నిర్వహించడానికి చిట్ ఫండ్లో చేరండి.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get memberSubtitleHasGroups =>
|
||||||
|
'మీ చిట్ ఫండ్ పెట్టుబడులు మరియు చెల్లింపులను ట్రాక్ చేయండి.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get navHome => 'హోమ్';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get navPayments => 'చెల్లింపులు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get navNotifications => 'నోటిఫికేషన్లు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get navProfile => 'ప్రొఫైల్';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get memberEmptyChitTitle => 'ఇంకా చిట్ ఫండ్లు లేవు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get memberEmptyChitBody =>
|
||||||
|
'మీరు ఇంకా ఏ చిట్ ఫండ్లోనూ చేరలేదు.\nప్రారంభించడానికి మీ మేనేజర్ను సంప్రదించండి!';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get memberHowToStartTitle => 'ఎలా ప్రారంభించాలి?';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get memberHowToStartBody =>
|
||||||
|
'1. మీ మేనేజర్ మిమ్మల్ని చిట్ గ్రూప్కు జోడిస్తారు\n'
|
||||||
|
'2. మీకు నోటిఫికేషన్ వస్తుంది\n'
|
||||||
|
'3. ఇక్కడ మీ చెల్లింపులను నిర్వహించండి!';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get unnamedGroupLong => 'పేరులేని గ్రూప్';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get labelTotalValue => 'మొత్తం విలువ';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get labelDuration => 'కాలపరిమితి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get monthsSuffix => 'నెలలు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get labelInstallment => 'వాయిదా';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get labelStatus => 'స్థితి';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get groupStatusPending => 'పెండింగ్';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get payNowButton => 'ఇప్పుడు చెల్లించు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get detailsButton => 'వివరాలు';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get memberInfoNotFound => 'సభ్య సమాచారం కనుగొనబడలేదు';
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
{
|
||||||
|
"@@locale": "te",
|
||||||
|
"appTitle": "లక్కీచిట్",
|
||||||
|
"settingsTitle": "సెట్టింగ్స్",
|
||||||
|
"sectionAppearance": "రూపం",
|
||||||
|
"sectionLanguage": "భాష",
|
||||||
|
"sectionAccount": "ఖాతా",
|
||||||
|
"sectionPaymentSettings": "చెల్లింపు సెట్టింగ్స్",
|
||||||
|
"sectionNotifications": "నోటిఫికేషన్లు",
|
||||||
|
"sectionAbout": "గురించి",
|
||||||
|
"languageTitle": "యాప్ భాష",
|
||||||
|
"languageSubtitle": "ఇంగ్లీషు లేదా తెలుగు",
|
||||||
|
"languageEnglish": "ఇంగ్లీషు",
|
||||||
|
"languageTelugu": "తెలుగు",
|
||||||
|
"chooseLanguageTitle": "భాష ఎంచుకోండి",
|
||||||
|
"themeTitle": "థీమ్",
|
||||||
|
"themeLight": "లైట్",
|
||||||
|
"themeDark": "డార్క్",
|
||||||
|
"themeSystem": "సిస్టమ్ డిఫాల్ట్",
|
||||||
|
"chooseThemeTitle": "థీమ్ ఎంచుకోండి",
|
||||||
|
"darkModeTitle": "డార్క్ మోడ్",
|
||||||
|
"darkModeSubtitle": "సిస్టమ్ సెట్టింగ్స్ను ఓవర్రైడ్ చేయండి",
|
||||||
|
"changePasswordTitle": "పాస్వర్డ్ మార్చండి",
|
||||||
|
"changePasswordSubtitle": "మీ పాస్వర్డ్ను నవీకరించండి",
|
||||||
|
"pushNotificationsTitle": "పుష్ నోటిఫికేషన్లు",
|
||||||
|
"pushNotificationsSubtitle": "పుష్ నోటిఫికేషన్లు అందుకోండి",
|
||||||
|
"paymentRemindersTitle": "చెల్లింపు రిమైండర్లు",
|
||||||
|
"paymentRemindersSubtitle": "రాబోయే చెల్లింపుల కోసం రిమైండర్లు",
|
||||||
|
"drawNotificationsTitle": "డ్రా నోటిఫికేషన్లు",
|
||||||
|
"drawNotificationsSubtitle": "లాటరీ డ్రాల కోసం అలర్ట్లు",
|
||||||
|
"upiIdTitle": "UPI ID",
|
||||||
|
"loading": "లోడ్ అవుతోంది…",
|
||||||
|
"active": "Active",
|
||||||
|
"notConfigured": "కాన్ఫిగర్ చేయలేదు",
|
||||||
|
"configureBackend": "backend/.env లో కాన్ఫిగర్ చేయండి",
|
||||||
|
"copyUpiIdTooltip": "UPI ID కాపీ చేయండి",
|
||||||
|
"upiCopiedClipboard": "UPI ID క్లిప్బోర్డ్కు కాపీ అయింది",
|
||||||
|
"paymentStatisticsTitle": "చెల్లింపు గణాంకాలు",
|
||||||
|
"paymentStatisticsSubtitle": "చెల్లింపు అంతర్దృష్టులను చూడండి",
|
||||||
|
"transactionFeesTitle": "లావాదేవీ ఫీజులు",
|
||||||
|
"transactionFeesSubtitle": "0% ఫీజులు • సంవత్సరానికి లక్షలు ఆదా!",
|
||||||
|
"free": "ఉచితం",
|
||||||
|
"appVersionTitle": "యాప్ వెర్షన్",
|
||||||
|
"privacyPolicyTitle": "గోప్యతా విధానం",
|
||||||
|
"termsOfServiceTitle": "సేవా నిబంధనలు",
|
||||||
|
"logout": "లాగ్ అవుట్",
|
||||||
|
"logoutConfirmTitle": "లాగ్ అవుట్",
|
||||||
|
"logoutConfirmMessage": "మీరు ఖచ్చితంగా లాగ్ అవుట్ కావాలనుకుంటున్నారా?",
|
||||||
|
"cancel": "రద్దు",
|
||||||
|
"close": "మూసివేయి",
|
||||||
|
"copied": "కాపీ అయింది!",
|
||||||
|
"profileComingSoon": "ప్రొఫైల్ పేజీ త్వరలో వస్తుంది",
|
||||||
|
"changePasswordComingSoon": "పాస్వర్డ్ మార్పు ఫీచర్ త్వరలో వస్తుంది",
|
||||||
|
"notificationComingSoon": "నోటిఫికేషన్ సెట్టింగ్స్ త్వరలో వస్తాయి",
|
||||||
|
"paymentStatsComingSoon": "చెల్లింపు గణాంకాలు త్వరలో వస్తాయి",
|
||||||
|
"privacyComingSoon": "గోప్యతా విధానం పేజీ త్వరలో వస్తుంది",
|
||||||
|
"termsComingSoon": "సేవా నిబంధనల పేజీ త్వరలో వస్తుంది",
|
||||||
|
"loggedOutSuccess": "విజయవంతంగా లాగ్ అవుట్ అయ్యారు",
|
||||||
|
"upiPaymentSettingsTitle": "UPI చెల్లింపు సెట్టింగ్స్",
|
||||||
|
"currentUpiId": "ప్రస్తుత UPI ID",
|
||||||
|
"upiNotConfiguredMessage": "UPI ID కాన్ఫిగర్ చేయలేదు. backend/.env ఫైల్ను నవీకరించండి.",
|
||||||
|
"howToUpdateUpi": "UPI ID ఎలా నవీకరించాలి",
|
||||||
|
"stepOpenEnv": "backend/.env ఫైల్ను తెరవండి",
|
||||||
|
"stepUpdatePhonepe": "PHONEPE_UPI_ID=your_upi@paytm ను నవీకరించండి",
|
||||||
|
"stepRestartBackend": "బ్యాకెండ్ సర్వర్ను రీస్టార్ట్ చేయండి",
|
||||||
|
"stepRefreshScreen": "ఈ స్క్రీన్ను రిఫ్రెష్ చేయండి",
|
||||||
|
"proTipTitle": "ప్రో టిప్",
|
||||||
|
"proTipBody": "సభ్యులు ఏ UPI యాప్తోనైనా (PhonePe, GPay, Paytm) మీ వ్యక్తిగత UPI IDకు నేరుగా 0% లావాదేవీ ఫీజుతో చెల్లించవచ్చు!"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
import 'package:luckychit/l10n/app_localizations.dart';
|
||||||
|
import 'package:luckychit/l10n/app_localizations_en.dart';
|
||||||
|
|
||||||
|
/// Localizations from a [BuildContext] (widgets).
|
||||||
|
extension AppL10n on BuildContext {
|
||||||
|
AppLocalizations get l10n {
|
||||||
|
final l = AppLocalizations.of(this);
|
||||||
|
assert(l != null, 'AppLocalizations not found — check GetMaterialApp delegates');
|
||||||
|
return l!;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Localizations when there is no [BuildContext] (GetX services, etc.).
|
||||||
|
/// Falls back to English if [Get.context] is missing or not localized yet.
|
||||||
|
final class L10nSvc {
|
||||||
|
L10nSvc._();
|
||||||
|
|
||||||
|
static AppLocalizations of() {
|
||||||
|
final ctx = Get.context;
|
||||||
|
final l = ctx != null ? AppLocalizations.of(ctx) : null;
|
||||||
|
return l ?? AppLocalizationsEn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,11 +4,14 @@ import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
import 'app.dart';
|
import 'app.dart';
|
||||||
import 'core/themes/app_theme.dart';
|
import 'core/themes/app_theme.dart';
|
||||||
import 'core/controllers/theme_controller.dart';
|
import 'core/controllers/theme_controller.dart';
|
||||||
|
import 'core/controllers/locale_controller.dart';
|
||||||
|
import 'l10n/app_localizations.dart';
|
||||||
|
|
||||||
void main() {
|
Future<void> main() async {
|
||||||
// Initialize theme controller
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
Get.put(ThemeController());
|
Get.put(ThemeController());
|
||||||
|
final localeController = Get.put(LocaleController());
|
||||||
|
await localeController.ensureLoaded();
|
||||||
runApp(const LuckyChitApp());
|
runApp(const LuckyChitApp());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -18,17 +21,22 @@ class LuckyChitApp extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ScreenUtilInit(
|
return ScreenUtilInit(
|
||||||
designSize: const Size(375, 812), // Mobile-first design size (iPhone X)
|
designSize: const Size(375, 812),
|
||||||
minTextAdapt: true,
|
minTextAdapt: true,
|
||||||
splitScreenMode: true,
|
splitScreenMode: true,
|
||||||
builder: (context, child) {
|
builder: (context, child) {
|
||||||
return GetMaterialApp(
|
return Obx(
|
||||||
title: 'LuckyChit',
|
() => GetMaterialApp(
|
||||||
debugShowCheckedModeBanner: false,
|
title: 'LuckyChit',
|
||||||
theme: AppTheme.lightTheme,
|
debugShowCheckedModeBanner: false,
|
||||||
darkTheme: AppTheme.darkTheme,
|
theme: AppTheme.lightTheme,
|
||||||
themeMode: ThemeController.to.themeMode,
|
darkTheme: AppTheme.darkTheme,
|
||||||
home: const App(),
|
themeMode: ThemeController.to.themeMode,
|
||||||
|
locale: LocaleController.to.locale.value,
|
||||||
|
supportedLocales: AppLocalizations.supportedLocales,
|
||||||
|
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||||
|
home: const App(),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
|
|
||||||
|
import '../../l10n/l10n_x.dart';
|
||||||
|
|
||||||
enum EmptyStateType {
|
enum EmptyStateType {
|
||||||
noGroups,
|
noGroups,
|
||||||
noMembers,
|
noMembers,
|
||||||
|
|
@ -31,7 +33,7 @@ class EmptyStateWidget extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final config = _getEmptyStateConfig(type);
|
final config = _getEmptyStateConfig(context, type);
|
||||||
|
|
||||||
return Center(
|
return Center(
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
|
|
@ -164,17 +166,17 @@ class EmptyStateWidget extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_EmptyStateConfig _getEmptyStateConfig(EmptyStateType type) {
|
_EmptyStateConfig _getEmptyStateConfig(BuildContext context, EmptyStateType type) {
|
||||||
|
final l = context.l10n;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case EmptyStateType.noGroups:
|
case EmptyStateType.noGroups:
|
||||||
return _EmptyStateConfig(
|
return _EmptyStateConfig(
|
||||||
icon: Icons.group_add_rounded,
|
icon: Icons.group_add_rounded,
|
||||||
iconColor: Colors.green.shade600,
|
iconColor: Colors.green.shade600,
|
||||||
backgroundColor: Colors.green.shade50,
|
backgroundColor: Colors.green.shade50,
|
||||||
title: 'No Chit Groups Yet',
|
title: l.emptyNoGroupsTitle,
|
||||||
message:
|
message: l.emptyNoGroupsMessage,
|
||||||
'You haven\'t created any chit groups yet.\nStart by creating your first group!',
|
actionLabel: l.emptyNoGroupsAction,
|
||||||
actionLabel: 'Create Group',
|
|
||||||
actionIcon: Icons.add_circle_outline,
|
actionIcon: Icons.add_circle_outline,
|
||||||
buttonColor: Colors.green.shade600,
|
buttonColor: Colors.green.shade600,
|
||||||
);
|
);
|
||||||
|
|
@ -184,10 +186,9 @@ class EmptyStateWidget extends StatelessWidget {
|
||||||
icon: Icons.people_outline_rounded,
|
icon: Icons.people_outline_rounded,
|
||||||
iconColor: Colors.blue.shade600,
|
iconColor: Colors.blue.shade600,
|
||||||
backgroundColor: Colors.blue.shade50,
|
backgroundColor: Colors.blue.shade50,
|
||||||
title: 'No Members Yet',
|
title: l.emptyNoMembersTitle,
|
||||||
message:
|
message: l.emptyNoMembersMessage,
|
||||||
'This group doesn\'t have any members yet.\nAdd members to get started!',
|
actionLabel: l.emptyNoMembersAction,
|
||||||
actionLabel: 'Add Members',
|
|
||||||
actionIcon: Icons.person_add,
|
actionIcon: Icons.person_add,
|
||||||
buttonColor: Colors.blue.shade600,
|
buttonColor: Colors.blue.shade600,
|
||||||
);
|
);
|
||||||
|
|
@ -197,10 +198,9 @@ class EmptyStateWidget extends StatelessWidget {
|
||||||
icon: Icons.payment_rounded,
|
icon: Icons.payment_rounded,
|
||||||
iconColor: Colors.orange.shade600,
|
iconColor: Colors.orange.shade600,
|
||||||
backgroundColor: Colors.orange.shade50,
|
backgroundColor: Colors.orange.shade50,
|
||||||
title: 'No Payments Yet',
|
title: l.emptyNoPaymentsTitle,
|
||||||
message:
|
message: l.emptyNoPaymentsMessage,
|
||||||
'No payment records found.\nPayments will appear here once recorded.',
|
actionLabel: l.emptyNoPaymentsAction,
|
||||||
actionLabel: 'Record Payment',
|
|
||||||
actionIcon: Icons.add,
|
actionIcon: Icons.add,
|
||||||
buttonColor: Colors.orange.shade600,
|
buttonColor: Colors.orange.shade600,
|
||||||
);
|
);
|
||||||
|
|
@ -210,10 +210,9 @@ class EmptyStateWidget extends StatelessWidget {
|
||||||
icon: Icons.history_rounded,
|
icon: Icons.history_rounded,
|
||||||
iconColor: Colors.purple.shade600,
|
iconColor: Colors.purple.shade600,
|
||||||
backgroundColor: Colors.purple.shade50,
|
backgroundColor: Colors.purple.shade50,
|
||||||
title: 'No Recent Activities',
|
title: l.emptyNoActivitiesTitle,
|
||||||
message:
|
message: l.emptyNoActivitiesMessage,
|
||||||
'Your recent activities will appear here.\nStart using the app to see updates!',
|
actionLabel: l.emptyNoActivitiesAction,
|
||||||
actionLabel: 'Refresh',
|
|
||||||
actionIcon: Icons.refresh,
|
actionIcon: Icons.refresh,
|
||||||
buttonColor: Colors.purple.shade600,
|
buttonColor: Colors.purple.shade600,
|
||||||
);
|
);
|
||||||
|
|
@ -223,10 +222,9 @@ class EmptyStateWidget extends StatelessWidget {
|
||||||
icon: Icons.search_off_rounded,
|
icon: Icons.search_off_rounded,
|
||||||
iconColor: Colors.grey.shade600,
|
iconColor: Colors.grey.shade600,
|
||||||
backgroundColor: Colors.grey.shade100,
|
backgroundColor: Colors.grey.shade100,
|
||||||
title: 'No Results Found',
|
title: l.emptyNoResultsTitle,
|
||||||
message:
|
message: l.emptyNoResultsMessage,
|
||||||
'We couldn\'t find what you\'re looking for.\nTry adjusting your search or filters.',
|
actionLabel: l.emptyNoResultsAction,
|
||||||
actionLabel: 'Clear Filters',
|
|
||||||
actionIcon: Icons.clear_all,
|
actionIcon: Icons.clear_all,
|
||||||
buttonColor: Colors.grey.shade600,
|
buttonColor: Colors.grey.shade600,
|
||||||
);
|
);
|
||||||
|
|
@ -236,10 +234,9 @@ class EmptyStateWidget extends StatelessWidget {
|
||||||
icon: Icons.error_outline_rounded,
|
icon: Icons.error_outline_rounded,
|
||||||
iconColor: Colors.red.shade600,
|
iconColor: Colors.red.shade600,
|
||||||
backgroundColor: Colors.red.shade50,
|
backgroundColor: Colors.red.shade50,
|
||||||
title: 'Oops! Something Went Wrong',
|
title: l.emptyErrorTitle,
|
||||||
message:
|
message: l.emptyErrorMessage,
|
||||||
'We encountered an error while loading data.\nPlease try again.',
|
actionLabel: l.emptyErrorAction,
|
||||||
actionLabel: 'Retry',
|
|
||||||
actionIcon: Icons.refresh,
|
actionIcon: Icons.refresh,
|
||||||
buttonColor: Colors.red.shade600,
|
buttonColor: Colors.red.shade600,
|
||||||
);
|
);
|
||||||
|
|
@ -249,10 +246,9 @@ class EmptyStateWidget extends StatelessWidget {
|
||||||
icon: Icons.wifi_off_rounded,
|
icon: Icons.wifi_off_rounded,
|
||||||
iconColor: Colors.red.shade600,
|
iconColor: Colors.red.shade600,
|
||||||
backgroundColor: Colors.red.shade50,
|
backgroundColor: Colors.red.shade50,
|
||||||
title: 'No Internet Connection',
|
title: l.emptyNoInternetTitle,
|
||||||
message:
|
message: l.emptyNoInternetMessage,
|
||||||
'Please check your internet connection\nand try again.',
|
actionLabel: l.emptyNoInternetAction,
|
||||||
actionLabel: 'Retry',
|
|
||||||
actionIcon: Icons.refresh,
|
actionIcon: Icons.refresh,
|
||||||
buttonColor: Colors.red.shade600,
|
buttonColor: Colors.red.shade600,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -270,6 +270,11 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.2.0"
|
version: "7.2.0"
|
||||||
|
flutter_localizations:
|
||||||
|
dependency: "direct main"
|
||||||
|
description: flutter
|
||||||
|
source: sdk
|
||||||
|
version: "0.0.0"
|
||||||
flutter_plugin_android_lifecycle:
|
flutter_plugin_android_lifecycle:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,8 @@ environment:
|
||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
flutter_localizations:
|
||||||
|
sdk: flutter
|
||||||
|
|
||||||
|
|
||||||
# UI and Icons
|
# UI and Icons
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue