Move apps to mobile directory structure

Relocated all app directories (client, design_system_viewer, staff) and their contents under the new 'apps/mobile' path. This change improves project organization and prepares for future platform-specific structuring.
This commit is contained in:
Achintha Isuru
2026-01-22 10:17:19 -05:00
parent 2f992ae5fa
commit cf59935ec8
982 changed files with 3 additions and 2532 deletions

View File

@@ -0,0 +1,31 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
/pubspec.lock
**/doc/api/
.dart_tool/
.flutter-plugins-dependencies
/build/
/coverage/

View File

@@ -0,0 +1,10 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: "3b62efc2a3da49882f43c372e0bc53daef7295a6"
channel: "stable"
project_type: package

View File

@@ -0,0 +1,4 @@
include: package:flutter_lints/flutter.yaml
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options

View File

@@ -0,0 +1,10 @@
export 'src/bloc/locale_bloc.dart';
export 'src/bloc/locale_event.dart';
export 'src/bloc/locale_state.dart';
export 'src/l10n/strings.g.dart';
export 'src/domain/repositories/locale_repository_interface.dart';
export 'src/domain/usecases/get_locale_use_case.dart';
export 'src/domain/usecases/set_locale_use_case.dart';
export 'src/data/repositories_impl/locale_repository_impl.dart';
export 'src/data/datasources/locale_local_data_source.dart';
export 'src/localization_module.dart';

View File

@@ -0,0 +1,56 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../domain/usecases/get_locale_use_case.dart';
import '../domain/usecases/set_locale_use_case.dart';
import '../l10n/strings.g.dart';
import 'locale_event.dart';
import 'locale_state.dart';
/// A [Bloc] that manages the application's locale state.
///
/// It coordinates the flow between user language requests and persistent storage
/// using [SetLocaleUseCase] and [GetLocaleUseCase].
class LocaleBloc extends Bloc<LocaleEvent, LocaleState> {
final GetLocaleUseCase getLocaleUseCase;
final SetLocaleUseCase setLocaleUseCase;
/// Creates a [LocaleBloc] with the required use cases.
LocaleBloc({required this.getLocaleUseCase, required this.setLocaleUseCase})
: super(LocaleState.initial()) {
on<ChangeLocale>(_onChangeLocale);
on<LoadLocale>(_onLoadLocale);
}
/// Handles the [ChangeLocale] event by saving it via the use case and emitting new state.
Future<void> _onChangeLocale(
ChangeLocale event,
Emitter<LocaleState> emit,
) async {
// 1. Update slang settings
LocaleSettings.setLocaleRaw(event.locale.languageCode);
// 2. Persist using Use Case
await setLocaleUseCase(event.locale);
// 3. Emit new state
emit(
LocaleState(
locale: event.locale,
supportedLocales: state.supportedLocales,
),
);
}
/// Handles the [LoadLocale] event by retrieving it via the use case and updating settings.
Future<void> _onLoadLocale(
LoadLocale event,
Emitter<LocaleState> emit,
) async {
final savedLocale = await getLocaleUseCase();
final locale = const Locale('es');
LocaleSettings.setLocaleRaw(locale.languageCode);
emit(LocaleState(locale: locale, supportedLocales: state.supportedLocales));
}
}

View File

@@ -0,0 +1,22 @@
import 'package:flutter/material.dart';
/// Base class for all locale-related events.
sealed class LocaleEvent {
/// Creates a [LocaleEvent].
const LocaleEvent();
}
/// Event triggered when the user wants to change the application locale.
class ChangeLocale extends LocaleEvent {
/// The new locale to apply.
final Locale locale;
/// Creates a [ChangeLocale] event.
const ChangeLocale(this.locale);
}
/// Event triggered to load the saved locale from persistent storage.
class LoadLocale extends LocaleEvent {
/// Creates a [LoadLocale] event.
const LoadLocale();
}

View File

@@ -0,0 +1,20 @@
import 'package:flutter/material.dart';
import '../l10n/strings.g.dart';
/// Represents the current state of the application's localization.
class LocaleState {
/// The current active locale.
final Locale locale;
/// The list of supported locales for the application.
final List<Locale> supportedLocales;
/// Creates a [LocaleState] with the specified [locale].
const LocaleState({required this.locale, required this.supportedLocales});
/// The initial state of the application, defaulting to English.
factory LocaleState.initial() => LocaleState(
locale: const Locale('es'),
supportedLocales: AppLocaleUtils.supportedLocales,
);
}

View File

@@ -0,0 +1,29 @@
import 'package:shared_preferences/shared_preferences.dart';
/// Interface for the local data source that manages locale persistence.
abstract interface class LocaleLocalDataSource {
/// Saves the language code to local storage.
Future<void> saveLanguageCode(String languageCode);
/// Retrieves the saved language code from local storage.
Future<String?> getLanguageCode();
}
/// Implementation of [LocaleLocalDataSource] using [SharedPreferencesAsync].
class LocaleLocalDataSourceImpl implements LocaleLocalDataSource {
static const String _localeKey = 'app_locale';
final SharedPreferencesAsync _sharedPreferences;
/// Creates a [LocaleLocalDataSourceImpl] with the required [SharedPreferencesAsync] instance.
LocaleLocalDataSourceImpl(this._sharedPreferences);
@override
Future<void> saveLanguageCode(String languageCode) async {
await _sharedPreferences.setString(_localeKey, languageCode);
}
@override
Future<String?> getLanguageCode() async {
return _sharedPreferences.getString(_localeKey);
}
}

View File

@@ -0,0 +1,28 @@
import 'dart:ui';
import '../../domain/repositories/locale_repository_interface.dart';
import '../datasources/locale_local_data_source.dart';
/// Implementation of [LocaleRepositoryInterface] that coordinates with a local data source.
///
/// This class handles the mapping between domain [Locale] objects and the raw
/// strings handled by the [LocaleLocalDataSource].
class LocaleRepositoryImpl implements LocaleRepositoryInterface {
final LocaleLocalDataSource _localDataSource;
/// Creates a [LocaleRepositoryImpl] with the provided [_localDataSource].
LocaleRepositoryImpl(this._localDataSource);
@override
Future<void> saveLocale(Locale locale) {
return _localDataSource.saveLanguageCode(locale.languageCode);
}
@override
Future<Locale?> getSavedLocale() async {
final languageCode = await _localDataSource.getLanguageCode();
if (languageCode != null) {
return Locale(languageCode);
}
return null;
}
}

View File

@@ -0,0 +1,17 @@
import 'dart:ui';
/// Interface for the locale repository.
///
/// This defines the contracts for persisting and retrieving the application's locale.
/// Implementations of this interface should handle the details of the storage mechanism.
abstract interface class LocaleRepositoryInterface {
/// Saves the specified [locale] to persistent storage.
///
/// Throws a [RepositoryException] if the operation fails.
Future<void> saveLocale(Locale locale);
/// Retrieves the saved [locale] from persistent storage.
///
/// Returns `null` if no locale has been previously saved.
Future<Locale?> getSavedLocale();
}

View File

@@ -0,0 +1,19 @@
import 'dart:ui';
import 'package:krow_core/core.dart';
import '../repositories/locale_repository_interface.dart';
/// Use case to retrieve the persisted application locale.
///
/// This class extends [NoInputUseCase] and interacts with [LocaleRepositoryInterface]
/// to fetch the saved locale.
class GetLocaleUseCase extends NoInputUseCase<Locale?> {
final LocaleRepositoryInterface _repository;
/// Creates a [GetLocaleUseCase] with the required [LocaleRepositoryInterface].
GetLocaleUseCase(this._repository);
@override
Future<Locale?> call() {
return _repository.getSavedLocale();
}
}

View File

@@ -0,0 +1,19 @@
import 'dart:ui';
import 'package:krow_core/core.dart';
import '../repositories/locale_repository_interface.dart';
/// Use case to save the application locale to persistent storage.
///
/// This class extends [UseCase] and interacts with [LocaleRepositoryInterface]
/// to save a given locale.
class SetLocaleUseCase extends UseCase<Locale, void> {
final LocaleRepositoryInterface _repository;
/// Creates a [SetLocaleUseCase] with the required [LocaleRepositoryInterface].
SetLocaleUseCase(this._repository);
@override
Future<void> call(Locale input) {
return _repository.saveLocale(input);
}
}

View File

@@ -0,0 +1,237 @@
{
"common": {
"ok": "OK",
"cancel": "Cancel",
"save": "Save",
"delete": "Delete",
"continue_text": "Continue"
},
"settings": {
"language": "Language",
"change_language": "Change Language"
},
"staff_authentication": {
"get_started_page": {
"title_part1": "Work, Grow, ",
"title_part2": "Elevate",
"subtitle": "Build your career in hospitality with \nflexibility and freedom.",
"sign_up_button": "Sign Up",
"log_in_button": "Log In"
},
"phone_verification_page": {
"validation_error": "Please enter a valid 10-digit phone number",
"send_code_button": "Send Code",
"enter_code_title": "Enter verification code",
"code_sent_message": "We sent a 6-digit code to ",
"code_sent_instruction": ". Enter it below to verify your account."
},
"phone_input": {
"title": "Verify your phone number",
"subtitle": "We'll send you a verification code to get started.",
"label": "Phone Number",
"hint": "Enter your number"
},
"otp_verification": {
"did_not_get_code": "Didn't get the code ?",
"resend_in": "Resend in $seconds s",
"resend_code": "Resend code"
},
"profile_setup_page": {
"step_indicator": "Step $current of $total",
"error_occurred": "An error occurred",
"complete_setup_button": "Complete Setup",
"steps": {
"basic": "Basic Info",
"location": "Location",
"experience": "Experience"
},
"basic_info": {
"title": "Let's get to know you",
"subtitle": "Tell us a bit about yourself",
"full_name_label": "Full Name *",
"full_name_hint": "John Smith",
"bio_label": "Short Bio",
"bio_hint": "Experienced hospitality professional..."
},
"location": {
"title": "Where do you want to work?",
"subtitle": "Add your preferred work locations",
"add_location_label": "Add Location *",
"add_location_hint": "City or ZIP code",
"add_button": "Add",
"max_distance": "Max Distance: $distance miles",
"min_dist_label": "5 mi",
"max_dist_label": "50 mi"
},
"experience": {
"title": "What are your skills?",
"subtitle": "Select all that apply",
"skills_label": "Skills *",
"industries_label": "Preferred Industries",
"skills": {
"food_service": "Food Service",
"bartending": "Bartending",
"warehouse": "Warehouse",
"retail": "Retail",
"events": "Events",
"customer_service": "Customer Service",
"cleaning": "Cleaning",
"security": "Security",
"driving": "Driving",
"cooking": "Cooking"
},
"industries": {
"hospitality": "Hospitality",
"food_service": "Food Service",
"warehouse": "Warehouse",
"events": "Events",
"retail": "Retail",
"healthcare": "Healthcare"
}
}
},
"common": {
"trouble_question": "Having trouble? ",
"contact_support": "Contact Support"
}
},
"client_authentication": {
"get_started_page": {
"title": "Take Control of Your\nShifts and Events",
"subtitle": "Streamline your operations with powerful tools to manage schedules, track performance, and keep your team on the same page—all in one place",
"sign_in_button": "Sign In",
"create_account_button": "Create Account"
},
"sign_in_page": {
"title": "Welcome Back",
"subtitle": "Sign in to manage your shifts and workers",
"email_label": "Email",
"email_hint": "Enter your email",
"password_label": "Password",
"password_hint": "Enter your password",
"forgot_password": "Forgot Password?",
"sign_in_button": "Sign In",
"or_divider": "or",
"social_apple": "Sign In with Apple",
"social_google": "Sign In with Google",
"no_account": "Don't have an account? ",
"sign_up_link": "Sign Up"
},
"sign_up_page": {
"title": "Create Account",
"subtitle": "Get started with Krow for your business",
"company_label": "Company Name",
"company_hint": "Enter company name",
"email_label": "Email",
"email_hint": "Enter your email",
"password_label": "Password",
"password_hint": "Create a password",
"confirm_password_label": "Confirm Password",
"confirm_password_hint": "Confirm your password",
"create_account_button": "Create Account",
"or_divider": "or",
"social_apple": "Sign Up with Apple",
"social_google": "Sign Up with Google",
"has_account": "Already have an account? ",
"sign_in_link": "Sign In"
}
},
"client_home": {
"dashboard": {
"welcome_back": "Welcome back",
"edit_mode_active": "Edit Mode Active",
"drag_instruction": "Drag to reorder, toggle visibility",
"reset": "Reset",
"metric_needed": "Needed",
"metric_filled": "Filled",
"metric_open": "Open",
"view_all": "View all",
"insight_lightbulb": "Save $amount/month",
"insight_tip": "Book 48hrs ahead for better rates"
},
"widgets": {
"actions": "Quick Actions",
"reorder": "Reorder",
"coverage": "Today's Coverage",
"spending": "Spending Insights",
"live_activity": "Live Activity"
},
"actions": {
"rapid": "RAPID",
"rapid_subtitle": "Urgent same-day",
"create_order": "Create Order",
"create_order_subtitle": "Schedule shifts",
"hubs": "Hubs",
"hubs_subtitle": "Clock-in points"
},
"reorder": {
"title": "REORDER",
"reorder_button": "Reorder",
"per_hr": "$amount/hr"
},
"form": {
"edit_reorder": "Edit & Reorder",
"post_new": "Post a New Shift",
"review_subtitle": "Review and edit the details before posting",
"date_label": "Date *",
"date_hint": "mm/dd/yyyy",
"location_label": "Location *",
"location_hint": "Business address",
"positions_title": "Positions",
"add_position": "Add Position",
"role_label": "Role *",
"role_hint": "Select role",
"start_time": "Start Time *",
"end_time": "End Time *",
"workers_needed": "Workers Needed *",
"hourly_rate": "Hourly Rate (\\$) *",
"post_shift": "Post Shift"
}
},
"client_settings": {
"profile": {
"title": "Profile",
"edit_profile": "Edit Profile",
"hubs": "Hubs",
"log_out": "Log Out",
"quick_links": "Quick Links",
"clock_in_hubs": "Clock-In Hubs",
"billing_payments": "Billing & Payments"
}
},
"client_hubs": {
"title": "Hubs",
"subtitle": "Manage clock-in locations",
"add_hub": "Add Hub",
"empty_state": {
"title": "No hubs yet",
"description": "Create clock-in stations for your locations",
"button": "Add Your First Hub"
},
"about_hubs": {
"title": "About Hubs",
"description": "Hubs are clock-in stations at your locations. Assign NFC tags to each hub so workers can quickly clock in/out using their phones."
},
"hub_card": {
"tag_label": "Tag: $id"
},
"add_hub_dialog": {
"title": "Add New Hub",
"name_label": "Hub Name *",
"name_hint": "e.g., Main Kitchen, Front Desk",
"location_label": "Location Name",
"location_hint": "e.g., Downtown Restaurant",
"address_label": "Address",
"address_hint": "Full address",
"create_button": "Create Hub"
},
"nfc_dialog": {
"title": "Identify NFC Tag",
"instruction": "Tap your phone to the NFC tag to identify it",
"scan_button": "Scan NFC Tag",
"tag_identified": "Tag Identified",
"assign_button": "Assign Tag"
}
}
}

View File

@@ -0,0 +1,236 @@
{
"common": {
"ok": "Aceptar",
"cancel": "Cancelar",
"save": "Guardar",
"delete": "Eliminar",
"continue_text": "Continuar"
},
"settings": {
"language": "Idioma",
"change_language": "Cambiar Idioma"
},
"staff_authentication": {
"get_started_page": {
"title_part1": "Trabaja, Crece, ",
"title_part2": "Elévate",
"subtitle": "Construye tu carrera en hostelería con \nflexibilidad y libertad.",
"sign_up_button": "Registrarse",
"log_in_button": "Iniciar sesión"
},
"phone_verification_page": {
"validation_error": "Por favor, ingresa un número de teléfono válido de 10 dígitos",
"send_code_button": "Enviar código",
"enter_code_title": "Ingresa el código de verificación",
"code_sent_message": "Enviamos un código de 6 dígitos a ",
"code_sent_instruction": ". Ingrésalo a continuación para verificar tu cuenta."
},
"phone_input": {
"title": "Verifica tu número de teléfono",
"subtitle": "Te enviaremos un código de verificación para comenzar.",
"label": "Número de teléfono",
"hint": "Ingresa tu número"
},
"otp_verification": {
"did_not_get_code": "¿No recibiste el código?",
"resend_in": "Reenviar en $seconds s",
"resend_code": "Reenviar código"
},
"profile_setup_page": {
"step_indicator": "Paso $current de $total",
"error_occurred": "Ocurrió un error",
"complete_setup_button": "Completar configuración",
"steps": {
"basic": "Información básica",
"location": "Ubicación",
"experience": "Experiencia"
},
"basic_info": {
"title": "Conozcámonos",
"subtitle": "Cuéntanos un poco sobre ti",
"full_name_label": "Nombre completo *",
"full_name_hint": "Juan Pérez",
"bio_label": "Biografía corta",
"bio_hint": "Profesional experimentado en hostelería..."
},
"location": {
"title": "¿Dónde quieres trabajar?",
"subtitle": "Agrega tus ubicaciones de trabajo preferidas",
"add_location_label": "Agregar ubicación *",
"add_location_hint": "Ciudad o código postal",
"add_button": "Agregar",
"max_distance": "Distancia máxima: $distance millas",
"min_dist_label": "5 mi",
"max_dist_label": "50 mi"
},
"experience": {
"title": "¿Cuáles son tus habilidades?",
"subtitle": "Selecciona todas las que correspondan",
"skills_label": "Habilidades *",
"industries_label": "Industrias preferidas",
"skills": {
"food_service": "Servicio de comida",
"bartending": "Preparación de bebidas",
"warehouse": "Almacén",
"retail": "Venta minorista",
"events": "Eventos",
"customer_service": "Servicio al cliente",
"cleaning": "Limpieza",
"security": "Seguridad",
"driving": "Conducción",
"cooking": "Cocina"
},
"industries": {
"hospitality": "Hostelería",
"food_service": "Servicio de comida",
"warehouse": "Almacén",
"events": "Eventos",
"retail": "Venta minorista",
"healthcare": "Atención médica"
}
}
},
"common": {
"trouble_question": "¿Tienes problemas? ",
"contact_support": "Contactar a soporte"
}
},
"client_authentication": {
"get_started_page": {
"title": "Toma el control de tus\nturnos y eventos",
"subtitle": "Optimiza tus operaciones con potentes herramientas para gestionar horarios, realizar un seguimiento del rendimiento y mantener a tu equipo en la misma página, todo en un solo lugar",
"sign_in_button": "Iniciar sesión",
"create_account_button": "Crear cuenta"
},
"sign_in_page": {
"title": "Bienvenido de nuevo",
"subtitle": "Inicia sesión para gestionar tus turnos y trabajadores",
"email_label": "Correo electrónico",
"email_hint": "Ingresa tu correo electrónico",
"password_label": "Contraseña",
"password_hint": "Ingresa tu contraseña",
"forgot_password": "¿Olvidaste tu contraseña?",
"sign_in_button": "Iniciar sesión",
"or_divider": "o",
"social_apple": "Iniciar sesión con Apple",
"social_google": "Iniciar sesión con Google",
"no_account": "¿No tienes una cuenta? ",
"sign_up_link": "Regístrate"
},
"sign_up_page": {
"title": "Crear cuenta",
"subtitle": "Comienza con Krow para tu negocio",
"company_label": "Nombre de la empresa",
"company_hint": "Ingresa el nombre de la empresa",
"email_label": "Correo electrónico",
"email_hint": "Ingresa tu correo electrónico",
"password_label": "Contraseña",
"password_hint": "Crea una contraseña",
"confirm_password_label": "Confirmar contraseña",
"confirm_password_hint": "Confirma tu contraseña",
"create_account_button": "Crear cuenta",
"or_divider": "o",
"social_apple": "Regístrate con Apple",
"social_google": "Regístrate con Google",
"has_account": "¿Ya tienes una cuenta? ",
"sign_in_link": "Iniciar sesión"
}
},
"client_home": {
"dashboard": {
"welcome_back": "Bienvenido de nuevo",
"edit_mode_active": "Modo Edición Activo",
"drag_instruction": "Arrastra para reordenar, cambia la visibilidad",
"reset": "Restablecer",
"metric_needed": "Necesario",
"metric_filled": "Lleno",
"metric_open": "Abierto",
"view_all": "Ver todo",
"insight_lightbulb": "Ahorra $amount/mes",
"insight_tip": "Reserva con 48h de antelación para mejores tarifas"
},
"widgets": {
"actions": "Acciones Rápidas",
"reorder": "Reordenar",
"coverage": "Cobertura de Hoy",
"spending": "Información de Gastos",
"live_activity": "Actividad en Vivo"
},
"actions": {
"rapid": "RÁPIDO",
"rapid_subtitle": "Urgente mismo día",
"create_order": "Crear Orden",
"create_order_subtitle": "Programar turnos",
"hubs": "Hubs",
"hubs_subtitle": "Puntos marcaje"
},
"reorder": {
"title": "REORDENAR",
"reorder_button": "Reordenar",
"per_hr": "$amount/hr"
},
"form": {
"edit_reorder": "Editar y Reordenar",
"post_new": "Publicar un Nuevo Turno",
"review_subtitle": "Revisa y edita los detalles antes de publicar",
"date_label": "Fecha *",
"date_hint": "mm/dd/aaaa",
"location_label": "Ubicación *",
"location_hint": "Dirección del negocio",
"positions_title": "Posiciones",
"add_position": "Añadir Posición",
"role_label": "Rol *",
"role_hint": "Seleccionar rol",
"start_time": "Hora de Inicio *",
"end_time": "Hora de Fin *",
"workers_needed": "Trabajadores Necesarios *",
"hourly_rate": "Tarifa por hora (\\$) *",
"post_shift": "Publicar Turno"
}
},
"client_settings": {
"profile": {
"title": "Perfil",
"edit_profile": "Editar Perfil",
"hubs": "Hubs",
"log_out": "Cerrar sesión",
"quick_links": "Enlaces rápidos",
"clock_in_hubs": "Hubs de Marcaje",
"billing_payments": "Facturación y Pagos"
}
},
"client_hubs": {
"title": "Hubs",
"subtitle": "Gestionar ubicaciones de marcaje",
"add_hub": "Añadir Hub",
"empty_state": {
"title": "No hay hubs aún",
"description": "Crea estaciones de marcaje para tus ubicaciones",
"button": "Añade tu primer Hub"
},
"about_hubs": {
"title": "Sobre los Hubs",
"description": "Los Hubs son estaciones de marcaje en tus ubicaciones. Asigna etiquetas NFC a cada hub para que los trabajadores puedan marcar entrada/salida rápidamente usando sus teléfonos."
},
"hub_card": {
"tag_label": "Etiqueta: $id"
},
"add_hub_dialog": {
"title": "Añadir Nuevo Hub",
"name_label": "Nombre del Hub *",
"name_hint": "ej., Cocina Principal, Recepción",
"location_label": "Nombre de la Ubicación",
"location_hint": "ej., Restaurante Centro",
"address_label": "Dirección",
"address_hint": "Dirección completa",
"create_button": "Crear Hub"
},
"nfc_dialog": {
"title": "Identificar Etiqueta NFC",
"instruction": "Acerque su teléfono a la etiqueta NFC para identificarla",
"scan_button": "Escanear Etiqueta NFC",
"tag_identified": "Etiqueta Identificada",
"assign_button": "Asignar Etiqueta"
}
}
}

View File

@@ -0,0 +1,46 @@
import 'package:flutter_modular/flutter_modular.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'data/datasources/locale_local_data_source.dart';
import 'data/repositories_impl/locale_repository_impl.dart';
import 'domain/repositories/locale_repository_interface.dart';
import 'domain/usecases/get_locale_use_case.dart';
import 'domain/usecases/set_locale_use_case.dart';
import 'bloc/locale_bloc.dart';
/// A [ModularModule] that manages localization dependencies.
///
/// This module registers all necessary data sources, repositories, use cases,
/// and the BLoC required for application-wide localization management.
class LocalizationModule extends Module {
@override
void binds(Injector i) {
// External Dependencies
i.addInstance<SharedPreferencesAsync>(SharedPreferencesAsync());
// Data Sources
i.addSingleton<LocaleLocalDataSource>(
() => LocaleLocalDataSourceImpl(i.get<SharedPreferencesAsync>()),
);
// Repositories
i.addSingleton<LocaleRepositoryInterface>(
() => LocaleRepositoryImpl(i.get<LocaleLocalDataSource>()),
);
// Use Cases
i.addSingleton<GetLocaleUseCase>(
() => GetLocaleUseCase(i.get<LocaleRepositoryInterface>()),
);
i.addSingleton<SetLocaleUseCase>(
() => SetLocaleUseCase(i.get<LocaleRepositoryInterface>()),
);
// BLoCs
i.addSingleton<LocaleBloc>(
() => LocaleBloc(
getLocaleUseCase: i.get<GetLocaleUseCase>(),
setLocaleUseCase: i.get<SetLocaleUseCase>(),
),
);
}
}

View File

@@ -0,0 +1,38 @@
name: core_localization
description: "Core localization package using Slang."
version: 0.0.1
publish_to: none
resolution: workspace
environment:
sdk: '>=3.10.0 <4.0.0'
flutter: ">=3.0.0"
dependencies:
flutter:
sdk: flutter
krow_core:
path: ../core
flutter_bloc: ^8.1.0
flutter_modular: ^6.3.2
slang: ^4.12.0
slang_flutter: ^4.12.0
shared_preferences: ^2.5.0
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^6.0.0
build_runner: ^2.4.15
slang_build_runner: ^4.12.0
flutter:
uses-material-design: true
slang:
base_locale: en
fallback_strategy: base_locale
input_directory: lib/src/l10n
input_file_pattern: .i18n.json
output_directory: lib/src/l10n
output_file_name: strings.g.dart

View File

@@ -0,0 +1,12 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:localization/localization.dart';
void main() {
test('adds one to input values', () {
final calculator = Calculator();
expect(calculator.addOne(2), 3);
expect(calculator.addOne(-7), -6);
expect(calculator.addOne(0), 1);
});
}