initalizing the mobile apps
This commit is contained in:
4
apps/packages/core/lib/core.dart
Normal file
4
apps/packages/core/lib/core.dart
Normal file
@@ -0,0 +1,4 @@
|
||||
library core;
|
||||
|
||||
export 'src/domain/arguments/usecase_argument.dart';
|
||||
export 'src/domain/usecases/usecase.dart';
|
||||
@@ -0,0 +1,12 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// Abstract base class for all use case arguments.
|
||||
///
|
||||
/// Use case arguments are data transfer objects (DTOs) used to pass data
|
||||
/// into a use case. They must extend [Equatable] to ensure value equality.
|
||||
abstract class UseCaseArgument extends Equatable {
|
||||
const UseCaseArgument();
|
||||
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
25
apps/packages/core/lib/src/domain/usecases/usecase.dart
Normal file
25
apps/packages/core/lib/src/domain/usecases/usecase.dart
Normal file
@@ -0,0 +1,25 @@
|
||||
/// Abstract base class for all use cases in the application.
|
||||
///
|
||||
/// Use cases encapsulate application-specific business rules and orchestrate
|
||||
/// the flow of data to and from the entities. They are typically invoked
|
||||
/// from the presentation layer (e.g., BLoCs, ViewModels) and interact with
|
||||
/// repositories from the data layer.
|
||||
///
|
||||
/// [Input] represents the type of data passed into the use case.
|
||||
/// [Output] represents the type of data returned by the use case.
|
||||
abstract class UseCase<Input, Output> {
|
||||
/// Executes the use case with the given [input].
|
||||
///
|
||||
/// This method should contain the core business logic of the use case.
|
||||
Future<Output> call(Input input);
|
||||
}
|
||||
|
||||
/// Abstract base class for use cases that do not require any input.
|
||||
///
|
||||
/// [Output] represents the type of data returned by the use case.
|
||||
abstract class NoInputUseCase<Output> {
|
||||
/// Executes the use case.
|
||||
///
|
||||
/// This method should contain the core business logic of the use case.
|
||||
Future<Output> call();
|
||||
}
|
||||
13
apps/packages/core/pubspec.yaml
Normal file
13
apps/packages/core/pubspec.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
name: krow_core
|
||||
description: Core utilities and shared logic.
|
||||
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
|
||||
31
apps/packages/core_localization/.gitignore
vendored
Normal file
31
apps/packages/core_localization/.gitignore
vendored
Normal 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/
|
||||
10
apps/packages/core_localization/.metadata
Normal file
10
apps/packages/core_localization/.metadata
Normal 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
|
||||
4
apps/packages/core_localization/analysis_options.yaml
Normal file
4
apps/packages/core_localization/analysis_options.yaml
Normal 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
|
||||
10
apps/packages/core_localization/lib/core_localization.dart
Normal file
10
apps/packages/core_localization/lib/core_localization.dart
Normal 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';
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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,
|
||||
);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
190
apps/packages/core_localization/lib/src/l10n/en.i18n.json
Normal file
190
apps/packages/core_localization/lib/src/l10n/en.i18n.json
Normal file
@@ -0,0 +1,190 @@
|
||||
{
|
||||
"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"
|
||||
},
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
189
apps/packages/core_localization/lib/src/l10n/es.i18n.json
Normal file
189
apps/packages/core_localization/lib/src/l10n/es.i18n.json
Normal file
@@ -0,0 +1,189 @@
|
||||
{
|
||||
"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"
|
||||
},
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
183
apps/packages/core_localization/lib/src/l10n/strings.g.dart
Normal file
183
apps/packages/core_localization/lib/src/l10n/strings.g.dart
Normal file
@@ -0,0 +1,183 @@
|
||||
/// Generated file. Do not edit.
|
||||
///
|
||||
/// Source: lib/src/l10n
|
||||
/// To regenerate, run: `dart run slang`
|
||||
///
|
||||
/// Locales: 2
|
||||
/// Strings: 276 (138 per locale)
|
||||
///
|
||||
/// Built on 2026-01-21 at 18:21 UTC
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: type=lint, unused_import
|
||||
// dart format off
|
||||
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:slang/generated.dart';
|
||||
import 'package:slang_flutter/slang_flutter.dart';
|
||||
export 'package:slang_flutter/slang_flutter.dart';
|
||||
|
||||
import 'strings_es.g.dart' deferred as l_es;
|
||||
part 'strings_en.g.dart';
|
||||
|
||||
/// Supported locales.
|
||||
///
|
||||
/// Usage:
|
||||
/// - LocaleSettings.setLocale(AppLocale.en) // set locale
|
||||
/// - Locale locale = AppLocale.en.flutterLocale // get flutter locale from enum
|
||||
/// - if (LocaleSettings.currentLocale == AppLocale.en) // locale check
|
||||
enum AppLocale with BaseAppLocale<AppLocale, Translations> {
|
||||
en(languageCode: 'en'),
|
||||
es(languageCode: 'es');
|
||||
|
||||
const AppLocale({
|
||||
required this.languageCode,
|
||||
this.scriptCode, // ignore: unused_element, unused_element_parameter
|
||||
this.countryCode, // ignore: unused_element, unused_element_parameter
|
||||
});
|
||||
|
||||
@override final String languageCode;
|
||||
@override final String? scriptCode;
|
||||
@override final String? countryCode;
|
||||
|
||||
@override
|
||||
Future<Translations> build({
|
||||
Map<String, Node>? overrides,
|
||||
PluralResolver? cardinalResolver,
|
||||
PluralResolver? ordinalResolver,
|
||||
}) async {
|
||||
switch (this) {
|
||||
case AppLocale.en:
|
||||
return TranslationsEn(
|
||||
overrides: overrides,
|
||||
cardinalResolver: cardinalResolver,
|
||||
ordinalResolver: ordinalResolver,
|
||||
);
|
||||
case AppLocale.es:
|
||||
await l_es.loadLibrary();
|
||||
return l_es.TranslationsEs(
|
||||
overrides: overrides,
|
||||
cardinalResolver: cardinalResolver,
|
||||
ordinalResolver: ordinalResolver,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Translations buildSync({
|
||||
Map<String, Node>? overrides,
|
||||
PluralResolver? cardinalResolver,
|
||||
PluralResolver? ordinalResolver,
|
||||
}) {
|
||||
switch (this) {
|
||||
case AppLocale.en:
|
||||
return TranslationsEn(
|
||||
overrides: overrides,
|
||||
cardinalResolver: cardinalResolver,
|
||||
ordinalResolver: ordinalResolver,
|
||||
);
|
||||
case AppLocale.es:
|
||||
return l_es.TranslationsEs(
|
||||
overrides: overrides,
|
||||
cardinalResolver: cardinalResolver,
|
||||
ordinalResolver: ordinalResolver,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets current instance managed by [LocaleSettings].
|
||||
Translations get translations => LocaleSettings.instance.getTranslations(this);
|
||||
}
|
||||
|
||||
/// Method A: Simple
|
||||
///
|
||||
/// No rebuild after locale change.
|
||||
/// Translation happens during initialization of the widget (call of t).
|
||||
/// Configurable via 'translate_var'.
|
||||
///
|
||||
/// Usage:
|
||||
/// String a = t.someKey.anotherKey;
|
||||
/// String b = t['someKey.anotherKey']; // Only for edge cases!
|
||||
Translations get t => LocaleSettings.instance.currentTranslations;
|
||||
|
||||
/// Method B: Advanced
|
||||
///
|
||||
/// All widgets using this method will trigger a rebuild when locale changes.
|
||||
/// Use this if you have e.g. a settings page where the user can select the locale during runtime.
|
||||
///
|
||||
/// Step 1:
|
||||
/// wrap your App with
|
||||
/// TranslationProvider(
|
||||
/// child: MyApp()
|
||||
/// );
|
||||
///
|
||||
/// Step 2:
|
||||
/// final t = Translations.of(context); // Get t variable.
|
||||
/// String a = t.someKey.anotherKey; // Use t variable.
|
||||
/// String b = t['someKey.anotherKey']; // Only for edge cases!
|
||||
class TranslationProvider extends BaseTranslationProvider<AppLocale, Translations> {
|
||||
TranslationProvider({required super.child}) : super(settings: LocaleSettings.instance);
|
||||
|
||||
static InheritedLocaleData<AppLocale, Translations> of(BuildContext context) => InheritedLocaleData.of<AppLocale, Translations>(context);
|
||||
}
|
||||
|
||||
/// Method B shorthand via [BuildContext] extension method.
|
||||
/// Configurable via 'translate_var'.
|
||||
///
|
||||
/// Usage (e.g. in a widget's build method):
|
||||
/// context.t.someKey.anotherKey
|
||||
extension BuildContextTranslationsExtension on BuildContext {
|
||||
Translations get t => TranslationProvider.of(this).translations;
|
||||
}
|
||||
|
||||
/// Manages all translation instances and the current locale
|
||||
class LocaleSettings extends BaseFlutterLocaleSettings<AppLocale, Translations> {
|
||||
LocaleSettings._() : super(
|
||||
utils: AppLocaleUtils.instance,
|
||||
lazy: true,
|
||||
);
|
||||
|
||||
static final instance = LocaleSettings._();
|
||||
|
||||
// static aliases (checkout base methods for documentation)
|
||||
static AppLocale get currentLocale => instance.currentLocale;
|
||||
static Stream<AppLocale> getLocaleStream() => instance.getLocaleStream();
|
||||
static Future<AppLocale> setLocale(AppLocale locale, {bool? listenToDeviceLocale = false}) => instance.setLocale(locale, listenToDeviceLocale: listenToDeviceLocale);
|
||||
static Future<AppLocale> setLocaleRaw(String rawLocale, {bool? listenToDeviceLocale = false}) => instance.setLocaleRaw(rawLocale, listenToDeviceLocale: listenToDeviceLocale);
|
||||
static Future<AppLocale> useDeviceLocale() => instance.useDeviceLocale();
|
||||
static Future<void> setPluralResolver({String? language, AppLocale? locale, PluralResolver? cardinalResolver, PluralResolver? ordinalResolver}) => instance.setPluralResolver(
|
||||
language: language,
|
||||
locale: locale,
|
||||
cardinalResolver: cardinalResolver,
|
||||
ordinalResolver: ordinalResolver,
|
||||
);
|
||||
|
||||
// synchronous versions
|
||||
static AppLocale setLocaleSync(AppLocale locale, {bool? listenToDeviceLocale = false}) => instance.setLocaleSync(locale, listenToDeviceLocale: listenToDeviceLocale);
|
||||
static AppLocale setLocaleRawSync(String rawLocale, {bool? listenToDeviceLocale = false}) => instance.setLocaleRawSync(rawLocale, listenToDeviceLocale: listenToDeviceLocale);
|
||||
static AppLocale useDeviceLocaleSync() => instance.useDeviceLocaleSync();
|
||||
static void setPluralResolverSync({String? language, AppLocale? locale, PluralResolver? cardinalResolver, PluralResolver? ordinalResolver}) => instance.setPluralResolverSync(
|
||||
language: language,
|
||||
locale: locale,
|
||||
cardinalResolver: cardinalResolver,
|
||||
ordinalResolver: ordinalResolver,
|
||||
);
|
||||
}
|
||||
|
||||
/// Provides utility functions without any side effects.
|
||||
class AppLocaleUtils extends BaseAppLocaleUtils<AppLocale, Translations> {
|
||||
AppLocaleUtils._() : super(
|
||||
baseLocale: AppLocale.en,
|
||||
locales: AppLocale.values,
|
||||
);
|
||||
|
||||
static final instance = AppLocaleUtils._();
|
||||
|
||||
// static aliases (checkout base methods for documentation)
|
||||
static AppLocale parse(String rawLocale) => instance.parse(rawLocale);
|
||||
static AppLocale parseLocaleParts({required String languageCode, String? scriptCode, String? countryCode}) => instance.parseLocaleParts(languageCode: languageCode, scriptCode: scriptCode, countryCode: countryCode);
|
||||
static AppLocale findDeviceLocale() => instance.findDeviceLocale();
|
||||
static List<Locale> get supportedLocales => instance.supportedLocales;
|
||||
static List<String> get supportedLocalesRaw => instance.supportedLocalesRaw;
|
||||
}
|
||||
861
apps/packages/core_localization/lib/src/l10n/strings_en.g.dart
Normal file
861
apps/packages/core_localization/lib/src/l10n/strings_en.g.dart
Normal file
@@ -0,0 +1,861 @@
|
||||
///
|
||||
/// Generated file. Do not edit.
|
||||
///
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: type=lint, unused_import
|
||||
// dart format off
|
||||
|
||||
part of 'strings.g.dart';
|
||||
|
||||
// Path: <root>
|
||||
typedef TranslationsEn = Translations; // ignore: unused_element
|
||||
class Translations with BaseTranslations<AppLocale, Translations> {
|
||||
/// Returns the current translations of the given [context].
|
||||
///
|
||||
/// Usage:
|
||||
/// final t = Translations.of(context);
|
||||
static Translations of(BuildContext context) => InheritedLocaleData.of<AppLocale, Translations>(context).translations;
|
||||
|
||||
/// You can call this constructor and build your own translation instance of this locale.
|
||||
/// Constructing via the enum [AppLocale.build] is preferred.
|
||||
Translations({Map<String, Node>? overrides, PluralResolver? cardinalResolver, PluralResolver? ordinalResolver, TranslationMetadata<AppLocale, Translations>? meta})
|
||||
: assert(overrides == null, 'Set "translation_overrides: true" in order to enable this feature.'),
|
||||
$meta = meta ?? TranslationMetadata(
|
||||
locale: AppLocale.en,
|
||||
overrides: overrides ?? {},
|
||||
cardinalResolver: cardinalResolver,
|
||||
ordinalResolver: ordinalResolver,
|
||||
) {
|
||||
$meta.setFlatMapFunction(_flatMapFunction);
|
||||
}
|
||||
|
||||
/// Metadata for the translations of <en>.
|
||||
@override final TranslationMetadata<AppLocale, Translations> $meta;
|
||||
|
||||
/// Access flat map
|
||||
dynamic operator[](String key) => $meta.getTranslation(key);
|
||||
|
||||
late final Translations _root = this; // ignore: unused_field
|
||||
|
||||
Translations $copyWith({TranslationMetadata<AppLocale, Translations>? meta}) => Translations(meta: meta ?? this.$meta);
|
||||
|
||||
// Translations
|
||||
late final TranslationsCommonEn common = TranslationsCommonEn._(_root);
|
||||
late final TranslationsSettingsEn settings = TranslationsSettingsEn._(_root);
|
||||
late final TranslationsStaffAuthenticationEn staff_authentication = TranslationsStaffAuthenticationEn._(_root);
|
||||
late final TranslationsClientAuthenticationEn client_authentication = TranslationsClientAuthenticationEn._(_root);
|
||||
late final TranslationsClientHomeEn client_home = TranslationsClientHomeEn._(_root);
|
||||
}
|
||||
|
||||
// Path: common
|
||||
class TranslationsCommonEn {
|
||||
TranslationsCommonEn._(this._root);
|
||||
|
||||
final Translations _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
|
||||
/// en: 'OK'
|
||||
String get ok => 'OK';
|
||||
|
||||
/// en: 'Cancel'
|
||||
String get cancel => 'Cancel';
|
||||
|
||||
/// en: 'Save'
|
||||
String get save => 'Save';
|
||||
|
||||
/// en: 'Delete'
|
||||
String get delete => 'Delete';
|
||||
|
||||
/// en: 'Continue'
|
||||
String get continue_text => 'Continue';
|
||||
}
|
||||
|
||||
// Path: settings
|
||||
class TranslationsSettingsEn {
|
||||
TranslationsSettingsEn._(this._root);
|
||||
|
||||
final Translations _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
|
||||
/// en: 'Language'
|
||||
String get language => 'Language';
|
||||
|
||||
/// en: 'Change Language'
|
||||
String get change_language => 'Change Language';
|
||||
}
|
||||
|
||||
// Path: staff_authentication
|
||||
class TranslationsStaffAuthenticationEn {
|
||||
TranslationsStaffAuthenticationEn._(this._root);
|
||||
|
||||
final Translations _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
late final TranslationsStaffAuthenticationGetStartedPageEn get_started_page = TranslationsStaffAuthenticationGetStartedPageEn._(_root);
|
||||
late final TranslationsStaffAuthenticationPhoneVerificationPageEn phone_verification_page = TranslationsStaffAuthenticationPhoneVerificationPageEn._(_root);
|
||||
late final TranslationsStaffAuthenticationPhoneInputEn phone_input = TranslationsStaffAuthenticationPhoneInputEn._(_root);
|
||||
late final TranslationsStaffAuthenticationOtpVerificationEn otp_verification = TranslationsStaffAuthenticationOtpVerificationEn._(_root);
|
||||
late final TranslationsStaffAuthenticationProfileSetupPageEn profile_setup_page = TranslationsStaffAuthenticationProfileSetupPageEn._(_root);
|
||||
late final TranslationsStaffAuthenticationCommonEn common = TranslationsStaffAuthenticationCommonEn._(_root);
|
||||
}
|
||||
|
||||
// Path: client_authentication
|
||||
class TranslationsClientAuthenticationEn {
|
||||
TranslationsClientAuthenticationEn._(this._root);
|
||||
|
||||
final Translations _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
late final TranslationsClientAuthenticationGetStartedPageEn get_started_page = TranslationsClientAuthenticationGetStartedPageEn._(_root);
|
||||
late final TranslationsClientAuthenticationSignInPageEn sign_in_page = TranslationsClientAuthenticationSignInPageEn._(_root);
|
||||
late final TranslationsClientAuthenticationSignUpPageEn sign_up_page = TranslationsClientAuthenticationSignUpPageEn._(_root);
|
||||
}
|
||||
|
||||
// Path: client_home
|
||||
class TranslationsClientHomeEn {
|
||||
TranslationsClientHomeEn._(this._root);
|
||||
|
||||
final Translations _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
|
||||
/// en: 'Shift order submitted successfully'
|
||||
String get shift_created_success => 'Shift order submitted successfully';
|
||||
|
||||
late final TranslationsClientHomeDashboardEn dashboard = TranslationsClientHomeDashboardEn._(_root);
|
||||
late final TranslationsClientHomeWidgetsEn widgets = TranslationsClientHomeWidgetsEn._(_root);
|
||||
late final TranslationsClientHomeActionsEn actions = TranslationsClientHomeActionsEn._(_root);
|
||||
late final TranslationsClientHomeReorderEn reorder = TranslationsClientHomeReorderEn._(_root);
|
||||
late final TranslationsClientHomeFormEn form = TranslationsClientHomeFormEn._(_root);
|
||||
}
|
||||
|
||||
// Path: staff_authentication.get_started_page
|
||||
class TranslationsStaffAuthenticationGetStartedPageEn {
|
||||
TranslationsStaffAuthenticationGetStartedPageEn._(this._root);
|
||||
|
||||
final Translations _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
|
||||
/// en: 'Work, Grow, '
|
||||
String get title_part1 => 'Work, Grow, ';
|
||||
|
||||
/// en: 'Elevate'
|
||||
String get title_part2 => 'Elevate';
|
||||
|
||||
/// en: 'Build your career in hospitality with flexibility and freedom.'
|
||||
String get subtitle => 'Build your career in hospitality with \nflexibility and freedom.';
|
||||
|
||||
/// en: 'Sign Up'
|
||||
String get sign_up_button => 'Sign Up';
|
||||
|
||||
/// en: 'Log In'
|
||||
String get log_in_button => 'Log In';
|
||||
}
|
||||
|
||||
// Path: staff_authentication.phone_verification_page
|
||||
class TranslationsStaffAuthenticationPhoneVerificationPageEn {
|
||||
TranslationsStaffAuthenticationPhoneVerificationPageEn._(this._root);
|
||||
|
||||
final Translations _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
|
||||
/// en: 'Please enter a valid 10-digit phone number'
|
||||
String get validation_error => 'Please enter a valid 10-digit phone number';
|
||||
|
||||
/// en: 'Send Code'
|
||||
String get send_code_button => 'Send Code';
|
||||
|
||||
/// en: 'Enter verification code'
|
||||
String get enter_code_title => 'Enter verification code';
|
||||
|
||||
/// en: 'We sent a 6-digit code to '
|
||||
String get code_sent_message => 'We sent a 6-digit code to ';
|
||||
|
||||
/// en: '. Enter it below to verify your account.'
|
||||
String get code_sent_instruction => '. Enter it below to verify your account.';
|
||||
}
|
||||
|
||||
// Path: staff_authentication.phone_input
|
||||
class TranslationsStaffAuthenticationPhoneInputEn {
|
||||
TranslationsStaffAuthenticationPhoneInputEn._(this._root);
|
||||
|
||||
final Translations _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
|
||||
/// en: 'Verify your phone number'
|
||||
String get title => 'Verify your phone number';
|
||||
|
||||
/// en: 'We'll send you a verification code to get started.'
|
||||
String get subtitle => 'We\'ll send you a verification code to get started.';
|
||||
|
||||
/// en: 'Phone Number'
|
||||
String get label => 'Phone Number';
|
||||
|
||||
/// en: 'Enter your number'
|
||||
String get hint => 'Enter your number';
|
||||
}
|
||||
|
||||
// Path: staff_authentication.otp_verification
|
||||
class TranslationsStaffAuthenticationOtpVerificationEn {
|
||||
TranslationsStaffAuthenticationOtpVerificationEn._(this._root);
|
||||
|
||||
final Translations _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
|
||||
/// en: 'Didn't get the code ?'
|
||||
String get did_not_get_code => 'Didn\'t get the code ?';
|
||||
|
||||
/// en: 'Resend in $seconds s'
|
||||
String resend_in({required Object seconds}) => 'Resend in ${seconds} s';
|
||||
|
||||
/// en: 'Resend code'
|
||||
String get resend_code => 'Resend code';
|
||||
}
|
||||
|
||||
// Path: staff_authentication.profile_setup_page
|
||||
class TranslationsStaffAuthenticationProfileSetupPageEn {
|
||||
TranslationsStaffAuthenticationProfileSetupPageEn._(this._root);
|
||||
|
||||
final Translations _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
|
||||
/// en: 'Step $current of $total'
|
||||
String step_indicator({required Object current, required Object total}) => 'Step ${current} of ${total}';
|
||||
|
||||
/// en: 'An error occurred'
|
||||
String get error_occurred => 'An error occurred';
|
||||
|
||||
/// en: 'Complete Setup'
|
||||
String get complete_setup_button => 'Complete Setup';
|
||||
|
||||
late final TranslationsStaffAuthenticationProfileSetupPageStepsEn steps = TranslationsStaffAuthenticationProfileSetupPageStepsEn._(_root);
|
||||
late final TranslationsStaffAuthenticationProfileSetupPageBasicInfoEn basic_info = TranslationsStaffAuthenticationProfileSetupPageBasicInfoEn._(_root);
|
||||
late final TranslationsStaffAuthenticationProfileSetupPageLocationEn location = TranslationsStaffAuthenticationProfileSetupPageLocationEn._(_root);
|
||||
late final TranslationsStaffAuthenticationProfileSetupPageExperienceEn experience = TranslationsStaffAuthenticationProfileSetupPageExperienceEn._(_root);
|
||||
}
|
||||
|
||||
// Path: staff_authentication.common
|
||||
class TranslationsStaffAuthenticationCommonEn {
|
||||
TranslationsStaffAuthenticationCommonEn._(this._root);
|
||||
|
||||
final Translations _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
|
||||
/// en: 'Having trouble? '
|
||||
String get trouble_question => 'Having trouble? ';
|
||||
|
||||
/// en: 'Contact Support'
|
||||
String get contact_support => 'Contact Support';
|
||||
}
|
||||
|
||||
// Path: client_authentication.get_started_page
|
||||
class TranslationsClientAuthenticationGetStartedPageEn {
|
||||
TranslationsClientAuthenticationGetStartedPageEn._(this._root);
|
||||
|
||||
final Translations _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
|
||||
/// en: 'Take Control of Your Shifts and Events'
|
||||
String get title => 'Take Control of Your\nShifts and Events';
|
||||
|
||||
/// en: 'Streamline your operations with powerful tools to manage schedules, track performance, and keep your team on the same page—all in one place'
|
||||
String get subtitle => 'Streamline your operations with powerful tools to manage schedules, track performance, and keep your team on the same page—all in one place';
|
||||
|
||||
/// en: 'Sign In'
|
||||
String get sign_in_button => 'Sign In';
|
||||
|
||||
/// en: 'Create Account'
|
||||
String get create_account_button => 'Create Account';
|
||||
}
|
||||
|
||||
// Path: client_authentication.sign_in_page
|
||||
class TranslationsClientAuthenticationSignInPageEn {
|
||||
TranslationsClientAuthenticationSignInPageEn._(this._root);
|
||||
|
||||
final Translations _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
|
||||
/// en: 'Welcome Back'
|
||||
String get title => 'Welcome Back';
|
||||
|
||||
/// en: 'Sign in to manage your shifts and workers'
|
||||
String get subtitle => 'Sign in to manage your shifts and workers';
|
||||
|
||||
/// en: 'Email'
|
||||
String get email_label => 'Email';
|
||||
|
||||
/// en: 'Enter your email'
|
||||
String get email_hint => 'Enter your email';
|
||||
|
||||
/// en: 'Password'
|
||||
String get password_label => 'Password';
|
||||
|
||||
/// en: 'Enter your password'
|
||||
String get password_hint => 'Enter your password';
|
||||
|
||||
/// en: 'Forgot Password?'
|
||||
String get forgot_password => 'Forgot Password?';
|
||||
|
||||
/// en: 'Sign In'
|
||||
String get sign_in_button => 'Sign In';
|
||||
|
||||
/// en: 'or'
|
||||
String get or_divider => 'or';
|
||||
|
||||
/// en: 'Sign In with Apple'
|
||||
String get social_apple => 'Sign In with Apple';
|
||||
|
||||
/// en: 'Sign In with Google'
|
||||
String get social_google => 'Sign In with Google';
|
||||
|
||||
/// en: 'Don't have an account? '
|
||||
String get no_account => 'Don\'t have an account? ';
|
||||
|
||||
/// en: 'Sign Up'
|
||||
String get sign_up_link => 'Sign Up';
|
||||
}
|
||||
|
||||
// Path: client_authentication.sign_up_page
|
||||
class TranslationsClientAuthenticationSignUpPageEn {
|
||||
TranslationsClientAuthenticationSignUpPageEn._(this._root);
|
||||
|
||||
final Translations _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
|
||||
/// en: 'Create Account'
|
||||
String get title => 'Create Account';
|
||||
|
||||
/// en: 'Get started with Krow for your business'
|
||||
String get subtitle => 'Get started with Krow for your business';
|
||||
|
||||
/// en: 'Company Name'
|
||||
String get company_label => 'Company Name';
|
||||
|
||||
/// en: 'Enter company name'
|
||||
String get company_hint => 'Enter company name';
|
||||
|
||||
/// en: 'Email'
|
||||
String get email_label => 'Email';
|
||||
|
||||
/// en: 'Enter your email'
|
||||
String get email_hint => 'Enter your email';
|
||||
|
||||
/// en: 'Password'
|
||||
String get password_label => 'Password';
|
||||
|
||||
/// en: 'Create a password'
|
||||
String get password_hint => 'Create a password';
|
||||
|
||||
/// en: 'Confirm Password'
|
||||
String get confirm_password_label => 'Confirm Password';
|
||||
|
||||
/// en: 'Confirm your password'
|
||||
String get confirm_password_hint => 'Confirm your password';
|
||||
|
||||
/// en: 'Create Account'
|
||||
String get create_account_button => 'Create Account';
|
||||
|
||||
/// en: 'or'
|
||||
String get or_divider => 'or';
|
||||
|
||||
/// en: 'Sign Up with Apple'
|
||||
String get social_apple => 'Sign Up with Apple';
|
||||
|
||||
/// en: 'Sign Up with Google'
|
||||
String get social_google => 'Sign Up with Google';
|
||||
|
||||
/// en: 'Already have an account? '
|
||||
String get has_account => 'Already have an account? ';
|
||||
|
||||
/// en: 'Sign In'
|
||||
String get sign_in_link => 'Sign In';
|
||||
}
|
||||
|
||||
// Path: client_home.dashboard
|
||||
class TranslationsClientHomeDashboardEn {
|
||||
TranslationsClientHomeDashboardEn._(this._root);
|
||||
|
||||
final Translations _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
|
||||
/// en: 'Welcome back'
|
||||
String get welcome_back => 'Welcome back';
|
||||
|
||||
/// en: 'Edit Mode Active'
|
||||
String get edit_mode_active => 'Edit Mode Active';
|
||||
|
||||
/// en: 'Drag to reorder, toggle visibility'
|
||||
String get drag_instruction => 'Drag to reorder, toggle visibility';
|
||||
|
||||
/// en: 'Reset'
|
||||
String get reset => 'Reset';
|
||||
|
||||
/// en: 'Needed'
|
||||
String get metric_needed => 'Needed';
|
||||
|
||||
/// en: 'Filled'
|
||||
String get metric_filled => 'Filled';
|
||||
|
||||
/// en: 'Open'
|
||||
String get metric_open => 'Open';
|
||||
|
||||
/// en: 'View all'
|
||||
String get view_all => 'View all';
|
||||
|
||||
/// en: 'Save $amount/month'
|
||||
String insight_lightbulb({required Object amount}) => 'Save ${amount}/month';
|
||||
|
||||
/// en: 'Book 48hrs ahead for better rates'
|
||||
String get insight_tip => 'Book 48hrs ahead for better rates';
|
||||
}
|
||||
|
||||
// Path: client_home.widgets
|
||||
class TranslationsClientHomeWidgetsEn {
|
||||
TranslationsClientHomeWidgetsEn._(this._root);
|
||||
|
||||
final Translations _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
|
||||
/// en: 'Quick Actions'
|
||||
String get actions => 'Quick Actions';
|
||||
|
||||
/// en: 'Reorder'
|
||||
String get reorder => 'Reorder';
|
||||
|
||||
/// en: 'Today's Coverage'
|
||||
String get coverage => 'Today\'s Coverage';
|
||||
|
||||
/// en: 'Spending Insights'
|
||||
String get spending => 'Spending Insights';
|
||||
|
||||
/// en: 'Live Activity'
|
||||
String get live_activity => 'Live Activity';
|
||||
}
|
||||
|
||||
// Path: client_home.actions
|
||||
class TranslationsClientHomeActionsEn {
|
||||
TranslationsClientHomeActionsEn._(this._root);
|
||||
|
||||
final Translations _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
|
||||
/// en: 'RAPID'
|
||||
String get rapid => 'RAPID';
|
||||
|
||||
/// en: 'Urgent same-day'
|
||||
String get rapid_subtitle => 'Urgent same-day';
|
||||
|
||||
/// en: 'Create Order'
|
||||
String get create_order => 'Create Order';
|
||||
|
||||
/// en: 'Schedule shifts'
|
||||
String get create_order_subtitle => 'Schedule shifts';
|
||||
}
|
||||
|
||||
// Path: client_home.reorder
|
||||
class TranslationsClientHomeReorderEn {
|
||||
TranslationsClientHomeReorderEn._(this._root);
|
||||
|
||||
final Translations _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
|
||||
/// en: 'REORDER'
|
||||
String get title => 'REORDER';
|
||||
|
||||
/// en: 'Reorder'
|
||||
String get reorder_button => 'Reorder';
|
||||
|
||||
/// en: '$amount/hr'
|
||||
String per_hr({required Object amount}) => '${amount}/hr';
|
||||
}
|
||||
|
||||
// Path: client_home.form
|
||||
class TranslationsClientHomeFormEn {
|
||||
TranslationsClientHomeFormEn._(this._root);
|
||||
|
||||
final Translations _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
|
||||
/// en: 'Edit & Reorder'
|
||||
String get edit_reorder => 'Edit & Reorder';
|
||||
|
||||
/// en: 'Post a New Shift'
|
||||
String get post_new => 'Post a New Shift';
|
||||
|
||||
/// en: 'Review and edit the details before posting'
|
||||
String get review_subtitle => 'Review and edit the details before posting';
|
||||
|
||||
/// en: 'Date *'
|
||||
String get date_label => 'Date *';
|
||||
|
||||
/// en: 'mm/dd/yyyy'
|
||||
String get date_hint => 'mm/dd/yyyy';
|
||||
|
||||
/// en: 'Location *'
|
||||
String get location_label => 'Location *';
|
||||
|
||||
/// en: 'Business address'
|
||||
String get location_hint => 'Business address';
|
||||
|
||||
/// en: 'Positions'
|
||||
String get positions_title => 'Positions';
|
||||
|
||||
/// en: 'Add Position'
|
||||
String get add_position => 'Add Position';
|
||||
|
||||
/// en: 'Role *'
|
||||
String get role_label => 'Role *';
|
||||
|
||||
/// en: 'Select role'
|
||||
String get role_hint => 'Select role';
|
||||
|
||||
/// en: 'Start Time *'
|
||||
String get start_time => 'Start Time *';
|
||||
|
||||
/// en: 'End Time *'
|
||||
String get end_time => 'End Time *';
|
||||
|
||||
/// en: 'Workers Needed *'
|
||||
String get workers_needed => 'Workers Needed *';
|
||||
|
||||
/// en: 'Hourly Rate (\$) *'
|
||||
String get hourly_rate => 'Hourly Rate (\$) *';
|
||||
|
||||
/// en: 'Post Shift'
|
||||
String get post_shift => 'Post Shift';
|
||||
}
|
||||
|
||||
// Path: staff_authentication.profile_setup_page.steps
|
||||
class TranslationsStaffAuthenticationProfileSetupPageStepsEn {
|
||||
TranslationsStaffAuthenticationProfileSetupPageStepsEn._(this._root);
|
||||
|
||||
final Translations _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
|
||||
/// en: 'Basic Info'
|
||||
String get basic => 'Basic Info';
|
||||
|
||||
/// en: 'Location'
|
||||
String get location => 'Location';
|
||||
|
||||
/// en: 'Experience'
|
||||
String get experience => 'Experience';
|
||||
}
|
||||
|
||||
// Path: staff_authentication.profile_setup_page.basic_info
|
||||
class TranslationsStaffAuthenticationProfileSetupPageBasicInfoEn {
|
||||
TranslationsStaffAuthenticationProfileSetupPageBasicInfoEn._(this._root);
|
||||
|
||||
final Translations _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
|
||||
/// en: 'Let's get to know you'
|
||||
String get title => 'Let\'s get to know you';
|
||||
|
||||
/// en: 'Tell us a bit about yourself'
|
||||
String get subtitle => 'Tell us a bit about yourself';
|
||||
|
||||
/// en: 'Full Name *'
|
||||
String get full_name_label => 'Full Name *';
|
||||
|
||||
/// en: 'John Smith'
|
||||
String get full_name_hint => 'John Smith';
|
||||
|
||||
/// en: 'Short Bio'
|
||||
String get bio_label => 'Short Bio';
|
||||
|
||||
/// en: 'Experienced hospitality professional...'
|
||||
String get bio_hint => 'Experienced hospitality professional...';
|
||||
}
|
||||
|
||||
// Path: staff_authentication.profile_setup_page.location
|
||||
class TranslationsStaffAuthenticationProfileSetupPageLocationEn {
|
||||
TranslationsStaffAuthenticationProfileSetupPageLocationEn._(this._root);
|
||||
|
||||
final Translations _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
|
||||
/// en: 'Where do you want to work?'
|
||||
String get title => 'Where do you want to work?';
|
||||
|
||||
/// en: 'Add your preferred work locations'
|
||||
String get subtitle => 'Add your preferred work locations';
|
||||
|
||||
/// en: 'Add Location *'
|
||||
String get add_location_label => 'Add Location *';
|
||||
|
||||
/// en: 'City or ZIP code'
|
||||
String get add_location_hint => 'City or ZIP code';
|
||||
|
||||
/// en: 'Add'
|
||||
String get add_button => 'Add';
|
||||
|
||||
/// en: 'Max Distance: $distance miles'
|
||||
String max_distance({required Object distance}) => 'Max Distance: ${distance} miles';
|
||||
|
||||
/// en: '5 mi'
|
||||
String get min_dist_label => '5 mi';
|
||||
|
||||
/// en: '50 mi'
|
||||
String get max_dist_label => '50 mi';
|
||||
}
|
||||
|
||||
// Path: staff_authentication.profile_setup_page.experience
|
||||
class TranslationsStaffAuthenticationProfileSetupPageExperienceEn {
|
||||
TranslationsStaffAuthenticationProfileSetupPageExperienceEn._(this._root);
|
||||
|
||||
final Translations _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
|
||||
/// en: 'What are your skills?'
|
||||
String get title => 'What are your skills?';
|
||||
|
||||
/// en: 'Select all that apply'
|
||||
String get subtitle => 'Select all that apply';
|
||||
|
||||
/// en: 'Skills *'
|
||||
String get skills_label => 'Skills *';
|
||||
|
||||
/// en: 'Preferred Industries'
|
||||
String get industries_label => 'Preferred Industries';
|
||||
|
||||
late final TranslationsStaffAuthenticationProfileSetupPageExperienceSkillsEn skills = TranslationsStaffAuthenticationProfileSetupPageExperienceSkillsEn._(_root);
|
||||
late final TranslationsStaffAuthenticationProfileSetupPageExperienceIndustriesEn industries = TranslationsStaffAuthenticationProfileSetupPageExperienceIndustriesEn._(_root);
|
||||
}
|
||||
|
||||
// Path: staff_authentication.profile_setup_page.experience.skills
|
||||
class TranslationsStaffAuthenticationProfileSetupPageExperienceSkillsEn {
|
||||
TranslationsStaffAuthenticationProfileSetupPageExperienceSkillsEn._(this._root);
|
||||
|
||||
final Translations _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
|
||||
/// en: 'Food Service'
|
||||
String get food_service => 'Food Service';
|
||||
|
||||
/// en: 'Bartending'
|
||||
String get bartending => 'Bartending';
|
||||
|
||||
/// en: 'Warehouse'
|
||||
String get warehouse => 'Warehouse';
|
||||
|
||||
/// en: 'Retail'
|
||||
String get retail => 'Retail';
|
||||
|
||||
/// en: 'Events'
|
||||
String get events => 'Events';
|
||||
|
||||
/// en: 'Customer Service'
|
||||
String get customer_service => 'Customer Service';
|
||||
|
||||
/// en: 'Cleaning'
|
||||
String get cleaning => 'Cleaning';
|
||||
|
||||
/// en: 'Security'
|
||||
String get security => 'Security';
|
||||
|
||||
/// en: 'Driving'
|
||||
String get driving => 'Driving';
|
||||
|
||||
/// en: 'Cooking'
|
||||
String get cooking => 'Cooking';
|
||||
}
|
||||
|
||||
// Path: staff_authentication.profile_setup_page.experience.industries
|
||||
class TranslationsStaffAuthenticationProfileSetupPageExperienceIndustriesEn {
|
||||
TranslationsStaffAuthenticationProfileSetupPageExperienceIndustriesEn._(this._root);
|
||||
|
||||
final Translations _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
|
||||
/// en: 'Hospitality'
|
||||
String get hospitality => 'Hospitality';
|
||||
|
||||
/// en: 'Food Service'
|
||||
String get food_service => 'Food Service';
|
||||
|
||||
/// en: 'Warehouse'
|
||||
String get warehouse => 'Warehouse';
|
||||
|
||||
/// en: 'Events'
|
||||
String get events => 'Events';
|
||||
|
||||
/// en: 'Retail'
|
||||
String get retail => 'Retail';
|
||||
|
||||
/// en: 'Healthcare'
|
||||
String get healthcare => 'Healthcare';
|
||||
}
|
||||
|
||||
/// The flat map containing all translations for locale <en>.
|
||||
/// Only for edge cases! For simple maps, use the map function of this library.
|
||||
///
|
||||
/// The Dart AOT compiler has issues with very large switch statements,
|
||||
/// so the map is split into smaller functions (512 entries each).
|
||||
extension on Translations {
|
||||
dynamic _flatMapFunction(String path) {
|
||||
return switch (path) {
|
||||
'common.ok' => 'OK',
|
||||
'common.cancel' => 'Cancel',
|
||||
'common.save' => 'Save',
|
||||
'common.delete' => 'Delete',
|
||||
'common.continue_text' => 'Continue',
|
||||
'settings.language' => 'Language',
|
||||
'settings.change_language' => 'Change Language',
|
||||
'staff_authentication.get_started_page.title_part1' => 'Work, Grow, ',
|
||||
'staff_authentication.get_started_page.title_part2' => 'Elevate',
|
||||
'staff_authentication.get_started_page.subtitle' => 'Build your career in hospitality with \nflexibility and freedom.',
|
||||
'staff_authentication.get_started_page.sign_up_button' => 'Sign Up',
|
||||
'staff_authentication.get_started_page.log_in_button' => 'Log In',
|
||||
'staff_authentication.phone_verification_page.validation_error' => 'Please enter a valid 10-digit phone number',
|
||||
'staff_authentication.phone_verification_page.send_code_button' => 'Send Code',
|
||||
'staff_authentication.phone_verification_page.enter_code_title' => 'Enter verification code',
|
||||
'staff_authentication.phone_verification_page.code_sent_message' => 'We sent a 6-digit code to ',
|
||||
'staff_authentication.phone_verification_page.code_sent_instruction' => '. Enter it below to verify your account.',
|
||||
'staff_authentication.phone_input.title' => 'Verify your phone number',
|
||||
'staff_authentication.phone_input.subtitle' => 'We\'ll send you a verification code to get started.',
|
||||
'staff_authentication.phone_input.label' => 'Phone Number',
|
||||
'staff_authentication.phone_input.hint' => 'Enter your number',
|
||||
'staff_authentication.otp_verification.did_not_get_code' => 'Didn\'t get the code ?',
|
||||
'staff_authentication.otp_verification.resend_in' => ({required Object seconds}) => 'Resend in ${seconds} s',
|
||||
'staff_authentication.otp_verification.resend_code' => 'Resend code',
|
||||
'staff_authentication.profile_setup_page.step_indicator' => ({required Object current, required Object total}) => 'Step ${current} of ${total}',
|
||||
'staff_authentication.profile_setup_page.error_occurred' => 'An error occurred',
|
||||
'staff_authentication.profile_setup_page.complete_setup_button' => 'Complete Setup',
|
||||
'staff_authentication.profile_setup_page.steps.basic' => 'Basic Info',
|
||||
'staff_authentication.profile_setup_page.steps.location' => 'Location',
|
||||
'staff_authentication.profile_setup_page.steps.experience' => 'Experience',
|
||||
'staff_authentication.profile_setup_page.basic_info.title' => 'Let\'s get to know you',
|
||||
'staff_authentication.profile_setup_page.basic_info.subtitle' => 'Tell us a bit about yourself',
|
||||
'staff_authentication.profile_setup_page.basic_info.full_name_label' => 'Full Name *',
|
||||
'staff_authentication.profile_setup_page.basic_info.full_name_hint' => 'John Smith',
|
||||
'staff_authentication.profile_setup_page.basic_info.bio_label' => 'Short Bio',
|
||||
'staff_authentication.profile_setup_page.basic_info.bio_hint' => 'Experienced hospitality professional...',
|
||||
'staff_authentication.profile_setup_page.location.title' => 'Where do you want to work?',
|
||||
'staff_authentication.profile_setup_page.location.subtitle' => 'Add your preferred work locations',
|
||||
'staff_authentication.profile_setup_page.location.add_location_label' => 'Add Location *',
|
||||
'staff_authentication.profile_setup_page.location.add_location_hint' => 'City or ZIP code',
|
||||
'staff_authentication.profile_setup_page.location.add_button' => 'Add',
|
||||
'staff_authentication.profile_setup_page.location.max_distance' => ({required Object distance}) => 'Max Distance: ${distance} miles',
|
||||
'staff_authentication.profile_setup_page.location.min_dist_label' => '5 mi',
|
||||
'staff_authentication.profile_setup_page.location.max_dist_label' => '50 mi',
|
||||
'staff_authentication.profile_setup_page.experience.title' => 'What are your skills?',
|
||||
'staff_authentication.profile_setup_page.experience.subtitle' => 'Select all that apply',
|
||||
'staff_authentication.profile_setup_page.experience.skills_label' => 'Skills *',
|
||||
'staff_authentication.profile_setup_page.experience.industries_label' => 'Preferred Industries',
|
||||
'staff_authentication.profile_setup_page.experience.skills.food_service' => 'Food Service',
|
||||
'staff_authentication.profile_setup_page.experience.skills.bartending' => 'Bartending',
|
||||
'staff_authentication.profile_setup_page.experience.skills.warehouse' => 'Warehouse',
|
||||
'staff_authentication.profile_setup_page.experience.skills.retail' => 'Retail',
|
||||
'staff_authentication.profile_setup_page.experience.skills.events' => 'Events',
|
||||
'staff_authentication.profile_setup_page.experience.skills.customer_service' => 'Customer Service',
|
||||
'staff_authentication.profile_setup_page.experience.skills.cleaning' => 'Cleaning',
|
||||
'staff_authentication.profile_setup_page.experience.skills.security' => 'Security',
|
||||
'staff_authentication.profile_setup_page.experience.skills.driving' => 'Driving',
|
||||
'staff_authentication.profile_setup_page.experience.skills.cooking' => 'Cooking',
|
||||
'staff_authentication.profile_setup_page.experience.industries.hospitality' => 'Hospitality',
|
||||
'staff_authentication.profile_setup_page.experience.industries.food_service' => 'Food Service',
|
||||
'staff_authentication.profile_setup_page.experience.industries.warehouse' => 'Warehouse',
|
||||
'staff_authentication.profile_setup_page.experience.industries.events' => 'Events',
|
||||
'staff_authentication.profile_setup_page.experience.industries.retail' => 'Retail',
|
||||
'staff_authentication.profile_setup_page.experience.industries.healthcare' => 'Healthcare',
|
||||
'staff_authentication.common.trouble_question' => 'Having trouble? ',
|
||||
'staff_authentication.common.contact_support' => 'Contact Support',
|
||||
'client_authentication.get_started_page.title' => 'Take Control of Your\nShifts and Events',
|
||||
'client_authentication.get_started_page.subtitle' => 'Streamline your operations with powerful tools to manage schedules, track performance, and keep your team on the same page—all in one place',
|
||||
'client_authentication.get_started_page.sign_in_button' => 'Sign In',
|
||||
'client_authentication.get_started_page.create_account_button' => 'Create Account',
|
||||
'client_authentication.sign_in_page.title' => 'Welcome Back',
|
||||
'client_authentication.sign_in_page.subtitle' => 'Sign in to manage your shifts and workers',
|
||||
'client_authentication.sign_in_page.email_label' => 'Email',
|
||||
'client_authentication.sign_in_page.email_hint' => 'Enter your email',
|
||||
'client_authentication.sign_in_page.password_label' => 'Password',
|
||||
'client_authentication.sign_in_page.password_hint' => 'Enter your password',
|
||||
'client_authentication.sign_in_page.forgot_password' => 'Forgot Password?',
|
||||
'client_authentication.sign_in_page.sign_in_button' => 'Sign In',
|
||||
'client_authentication.sign_in_page.or_divider' => 'or',
|
||||
'client_authentication.sign_in_page.social_apple' => 'Sign In with Apple',
|
||||
'client_authentication.sign_in_page.social_google' => 'Sign In with Google',
|
||||
'client_authentication.sign_in_page.no_account' => 'Don\'t have an account? ',
|
||||
'client_authentication.sign_in_page.sign_up_link' => 'Sign Up',
|
||||
'client_authentication.sign_up_page.title' => 'Create Account',
|
||||
'client_authentication.sign_up_page.subtitle' => 'Get started with Krow for your business',
|
||||
'client_authentication.sign_up_page.company_label' => 'Company Name',
|
||||
'client_authentication.sign_up_page.company_hint' => 'Enter company name',
|
||||
'client_authentication.sign_up_page.email_label' => 'Email',
|
||||
'client_authentication.sign_up_page.email_hint' => 'Enter your email',
|
||||
'client_authentication.sign_up_page.password_label' => 'Password',
|
||||
'client_authentication.sign_up_page.password_hint' => 'Create a password',
|
||||
'client_authentication.sign_up_page.confirm_password_label' => 'Confirm Password',
|
||||
'client_authentication.sign_up_page.confirm_password_hint' => 'Confirm your password',
|
||||
'client_authentication.sign_up_page.create_account_button' => 'Create Account',
|
||||
'client_authentication.sign_up_page.or_divider' => 'or',
|
||||
'client_authentication.sign_up_page.social_apple' => 'Sign Up with Apple',
|
||||
'client_authentication.sign_up_page.social_google' => 'Sign Up with Google',
|
||||
'client_authentication.sign_up_page.has_account' => 'Already have an account? ',
|
||||
'client_authentication.sign_up_page.sign_in_link' => 'Sign In',
|
||||
'client_home.shift_created_success' => 'Shift order submitted successfully',
|
||||
'client_home.dashboard.welcome_back' => 'Welcome back',
|
||||
'client_home.dashboard.edit_mode_active' => 'Edit Mode Active',
|
||||
'client_home.dashboard.drag_instruction' => 'Drag to reorder, toggle visibility',
|
||||
'client_home.dashboard.reset' => 'Reset',
|
||||
'client_home.dashboard.metric_needed' => 'Needed',
|
||||
'client_home.dashboard.metric_filled' => 'Filled',
|
||||
'client_home.dashboard.metric_open' => 'Open',
|
||||
'client_home.dashboard.view_all' => 'View all',
|
||||
'client_home.dashboard.insight_lightbulb' => ({required Object amount}) => 'Save ${amount}/month',
|
||||
'client_home.dashboard.insight_tip' => 'Book 48hrs ahead for better rates',
|
||||
'client_home.widgets.actions' => 'Quick Actions',
|
||||
'client_home.widgets.reorder' => 'Reorder',
|
||||
'client_home.widgets.coverage' => 'Today\'s Coverage',
|
||||
'client_home.widgets.spending' => 'Spending Insights',
|
||||
'client_home.widgets.live_activity' => 'Live Activity',
|
||||
'client_home.actions.rapid' => 'RAPID',
|
||||
'client_home.actions.rapid_subtitle' => 'Urgent same-day',
|
||||
'client_home.actions.create_order' => 'Create Order',
|
||||
'client_home.actions.create_order_subtitle' => 'Schedule shifts',
|
||||
'client_home.reorder.title' => 'REORDER',
|
||||
'client_home.reorder.reorder_button' => 'Reorder',
|
||||
'client_home.reorder.per_hr' => ({required Object amount}) => '${amount}/hr',
|
||||
'client_home.form.edit_reorder' => 'Edit & Reorder',
|
||||
'client_home.form.post_new' => 'Post a New Shift',
|
||||
'client_home.form.review_subtitle' => 'Review and edit the details before posting',
|
||||
'client_home.form.date_label' => 'Date *',
|
||||
'client_home.form.date_hint' => 'mm/dd/yyyy',
|
||||
'client_home.form.location_label' => 'Location *',
|
||||
'client_home.form.location_hint' => 'Business address',
|
||||
'client_home.form.positions_title' => 'Positions',
|
||||
'client_home.form.add_position' => 'Add Position',
|
||||
'client_home.form.role_label' => 'Role *',
|
||||
'client_home.form.role_hint' => 'Select role',
|
||||
'client_home.form.start_time' => 'Start Time *',
|
||||
'client_home.form.end_time' => 'End Time *',
|
||||
'client_home.form.workers_needed' => 'Workers Needed *',
|
||||
'client_home.form.hourly_rate' => 'Hourly Rate (\$) *',
|
||||
'client_home.form.post_shift' => 'Post Shift',
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
}
|
||||
579
apps/packages/core_localization/lib/src/l10n/strings_es.g.dart
Normal file
579
apps/packages/core_localization/lib/src/l10n/strings_es.g.dart
Normal file
@@ -0,0 +1,579 @@
|
||||
///
|
||||
/// Generated file. Do not edit.
|
||||
///
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: type=lint, unused_import
|
||||
// dart format off
|
||||
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:slang/generated.dart';
|
||||
import 'strings.g.dart';
|
||||
|
||||
// Path: <root>
|
||||
class TranslationsEs with BaseTranslations<AppLocale, Translations> implements Translations {
|
||||
/// You can call this constructor and build your own translation instance of this locale.
|
||||
/// Constructing via the enum [AppLocale.build] is preferred.
|
||||
TranslationsEs({Map<String, Node>? overrides, PluralResolver? cardinalResolver, PluralResolver? ordinalResolver, TranslationMetadata<AppLocale, Translations>? meta})
|
||||
: assert(overrides == null, 'Set "translation_overrides: true" in order to enable this feature.'),
|
||||
$meta = meta ?? TranslationMetadata(
|
||||
locale: AppLocale.es,
|
||||
overrides: overrides ?? {},
|
||||
cardinalResolver: cardinalResolver,
|
||||
ordinalResolver: ordinalResolver,
|
||||
) {
|
||||
$meta.setFlatMapFunction(_flatMapFunction);
|
||||
}
|
||||
|
||||
/// Metadata for the translations of <es>.
|
||||
@override final TranslationMetadata<AppLocale, Translations> $meta;
|
||||
|
||||
/// Access flat map
|
||||
@override dynamic operator[](String key) => $meta.getTranslation(key);
|
||||
|
||||
late final TranslationsEs _root = this; // ignore: unused_field
|
||||
|
||||
@override
|
||||
TranslationsEs $copyWith({TranslationMetadata<AppLocale, Translations>? meta}) => TranslationsEs(meta: meta ?? this.$meta);
|
||||
|
||||
// Translations
|
||||
@override late final _TranslationsCommonEs common = _TranslationsCommonEs._(_root);
|
||||
@override late final _TranslationsSettingsEs settings = _TranslationsSettingsEs._(_root);
|
||||
@override late final _TranslationsStaffAuthenticationEs staff_authentication = _TranslationsStaffAuthenticationEs._(_root);
|
||||
@override late final _TranslationsClientAuthenticationEs client_authentication = _TranslationsClientAuthenticationEs._(_root);
|
||||
@override late final _TranslationsClientHomeEs client_home = _TranslationsClientHomeEs._(_root);
|
||||
}
|
||||
|
||||
// Path: common
|
||||
class _TranslationsCommonEs implements TranslationsCommonEn {
|
||||
_TranslationsCommonEs._(this._root);
|
||||
|
||||
final TranslationsEs _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override String get ok => 'Aceptar';
|
||||
@override String get cancel => 'Cancelar';
|
||||
@override String get save => 'Guardar';
|
||||
@override String get delete => 'Eliminar';
|
||||
@override String get continue_text => 'Continuar';
|
||||
}
|
||||
|
||||
// Path: settings
|
||||
class _TranslationsSettingsEs implements TranslationsSettingsEn {
|
||||
_TranslationsSettingsEs._(this._root);
|
||||
|
||||
final TranslationsEs _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override String get language => 'Idioma';
|
||||
@override String get change_language => 'Cambiar Idioma';
|
||||
}
|
||||
|
||||
// Path: staff_authentication
|
||||
class _TranslationsStaffAuthenticationEs implements TranslationsStaffAuthenticationEn {
|
||||
_TranslationsStaffAuthenticationEs._(this._root);
|
||||
|
||||
final TranslationsEs _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override late final _TranslationsStaffAuthenticationGetStartedPageEs get_started_page = _TranslationsStaffAuthenticationGetStartedPageEs._(_root);
|
||||
@override late final _TranslationsStaffAuthenticationPhoneVerificationPageEs phone_verification_page = _TranslationsStaffAuthenticationPhoneVerificationPageEs._(_root);
|
||||
@override late final _TranslationsStaffAuthenticationPhoneInputEs phone_input = _TranslationsStaffAuthenticationPhoneInputEs._(_root);
|
||||
@override late final _TranslationsStaffAuthenticationOtpVerificationEs otp_verification = _TranslationsStaffAuthenticationOtpVerificationEs._(_root);
|
||||
@override late final _TranslationsStaffAuthenticationProfileSetupPageEs profile_setup_page = _TranslationsStaffAuthenticationProfileSetupPageEs._(_root);
|
||||
@override late final _TranslationsStaffAuthenticationCommonEs common = _TranslationsStaffAuthenticationCommonEs._(_root);
|
||||
}
|
||||
|
||||
// Path: client_authentication
|
||||
class _TranslationsClientAuthenticationEs implements TranslationsClientAuthenticationEn {
|
||||
_TranslationsClientAuthenticationEs._(this._root);
|
||||
|
||||
final TranslationsEs _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override late final _TranslationsClientAuthenticationGetStartedPageEs get_started_page = _TranslationsClientAuthenticationGetStartedPageEs._(_root);
|
||||
@override late final _TranslationsClientAuthenticationSignInPageEs sign_in_page = _TranslationsClientAuthenticationSignInPageEs._(_root);
|
||||
@override late final _TranslationsClientAuthenticationSignUpPageEs sign_up_page = _TranslationsClientAuthenticationSignUpPageEs._(_root);
|
||||
}
|
||||
|
||||
// Path: client_home
|
||||
class _TranslationsClientHomeEs implements TranslationsClientHomeEn {
|
||||
_TranslationsClientHomeEs._(this._root);
|
||||
|
||||
final TranslationsEs _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override String get shift_created_success => 'Orden de turno enviada con éxito';
|
||||
@override late final _TranslationsClientHomeDashboardEs dashboard = _TranslationsClientHomeDashboardEs._(_root);
|
||||
@override late final _TranslationsClientHomeWidgetsEs widgets = _TranslationsClientHomeWidgetsEs._(_root);
|
||||
@override late final _TranslationsClientHomeActionsEs actions = _TranslationsClientHomeActionsEs._(_root);
|
||||
@override late final _TranslationsClientHomeReorderEs reorder = _TranslationsClientHomeReorderEs._(_root);
|
||||
@override late final _TranslationsClientHomeFormEs form = _TranslationsClientHomeFormEs._(_root);
|
||||
}
|
||||
|
||||
// Path: staff_authentication.get_started_page
|
||||
class _TranslationsStaffAuthenticationGetStartedPageEs implements TranslationsStaffAuthenticationGetStartedPageEn {
|
||||
_TranslationsStaffAuthenticationGetStartedPageEs._(this._root);
|
||||
|
||||
final TranslationsEs _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override String get title_part1 => 'Trabaja, Crece, ';
|
||||
@override String get title_part2 => 'Elévate';
|
||||
@override String get subtitle => 'Construye tu carrera en hostelería con \nflexibilidad y libertad.';
|
||||
@override String get sign_up_button => 'Registrarse';
|
||||
@override String get log_in_button => 'Iniciar sesión';
|
||||
}
|
||||
|
||||
// Path: staff_authentication.phone_verification_page
|
||||
class _TranslationsStaffAuthenticationPhoneVerificationPageEs implements TranslationsStaffAuthenticationPhoneVerificationPageEn {
|
||||
_TranslationsStaffAuthenticationPhoneVerificationPageEs._(this._root);
|
||||
|
||||
final TranslationsEs _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override String get validation_error => 'Por favor, ingresa un número de teléfono válido de 10 dígitos';
|
||||
@override String get send_code_button => 'Enviar código';
|
||||
@override String get enter_code_title => 'Ingresa el código de verificación';
|
||||
@override String get code_sent_message => 'Enviamos un código de 6 dígitos a ';
|
||||
@override String get code_sent_instruction => '. Ingrésalo a continuación para verificar tu cuenta.';
|
||||
}
|
||||
|
||||
// Path: staff_authentication.phone_input
|
||||
class _TranslationsStaffAuthenticationPhoneInputEs implements TranslationsStaffAuthenticationPhoneInputEn {
|
||||
_TranslationsStaffAuthenticationPhoneInputEs._(this._root);
|
||||
|
||||
final TranslationsEs _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override String get title => 'Verifica tu número de teléfono';
|
||||
@override String get subtitle => 'Te enviaremos un código de verificación para comenzar.';
|
||||
@override String get label => 'Número de teléfono';
|
||||
@override String get hint => 'Ingresa tu número';
|
||||
}
|
||||
|
||||
// Path: staff_authentication.otp_verification
|
||||
class _TranslationsStaffAuthenticationOtpVerificationEs implements TranslationsStaffAuthenticationOtpVerificationEn {
|
||||
_TranslationsStaffAuthenticationOtpVerificationEs._(this._root);
|
||||
|
||||
final TranslationsEs _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override String get did_not_get_code => '¿No recibiste el código?';
|
||||
@override String resend_in({required Object seconds}) => 'Reenviar en ${seconds} s';
|
||||
@override String get resend_code => 'Reenviar código';
|
||||
}
|
||||
|
||||
// Path: staff_authentication.profile_setup_page
|
||||
class _TranslationsStaffAuthenticationProfileSetupPageEs implements TranslationsStaffAuthenticationProfileSetupPageEn {
|
||||
_TranslationsStaffAuthenticationProfileSetupPageEs._(this._root);
|
||||
|
||||
final TranslationsEs _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override String step_indicator({required Object current, required Object total}) => 'Paso ${current} de ${total}';
|
||||
@override String get error_occurred => 'Ocurrió un error';
|
||||
@override String get complete_setup_button => 'Completar configuración';
|
||||
@override late final _TranslationsStaffAuthenticationProfileSetupPageStepsEs steps = _TranslationsStaffAuthenticationProfileSetupPageStepsEs._(_root);
|
||||
@override late final _TranslationsStaffAuthenticationProfileSetupPageBasicInfoEs basic_info = _TranslationsStaffAuthenticationProfileSetupPageBasicInfoEs._(_root);
|
||||
@override late final _TranslationsStaffAuthenticationProfileSetupPageLocationEs location = _TranslationsStaffAuthenticationProfileSetupPageLocationEs._(_root);
|
||||
@override late final _TranslationsStaffAuthenticationProfileSetupPageExperienceEs experience = _TranslationsStaffAuthenticationProfileSetupPageExperienceEs._(_root);
|
||||
}
|
||||
|
||||
// Path: staff_authentication.common
|
||||
class _TranslationsStaffAuthenticationCommonEs implements TranslationsStaffAuthenticationCommonEn {
|
||||
_TranslationsStaffAuthenticationCommonEs._(this._root);
|
||||
|
||||
final TranslationsEs _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override String get trouble_question => '¿Tienes problemas? ';
|
||||
@override String get contact_support => 'Contactar a soporte';
|
||||
}
|
||||
|
||||
// Path: client_authentication.get_started_page
|
||||
class _TranslationsClientAuthenticationGetStartedPageEs implements TranslationsClientAuthenticationGetStartedPageEn {
|
||||
_TranslationsClientAuthenticationGetStartedPageEs._(this._root);
|
||||
|
||||
final TranslationsEs _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override String get title => 'Toma el control de tus\nturnos y eventos';
|
||||
@override String get 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';
|
||||
@override String get sign_in_button => 'Iniciar sesión';
|
||||
@override String get create_account_button => 'Crear cuenta';
|
||||
}
|
||||
|
||||
// Path: client_authentication.sign_in_page
|
||||
class _TranslationsClientAuthenticationSignInPageEs implements TranslationsClientAuthenticationSignInPageEn {
|
||||
_TranslationsClientAuthenticationSignInPageEs._(this._root);
|
||||
|
||||
final TranslationsEs _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override String get title => 'Bienvenido de nuevo';
|
||||
@override String get subtitle => 'Inicia sesión para gestionar tus turnos y trabajadores';
|
||||
@override String get email_label => 'Correo electrónico';
|
||||
@override String get email_hint => 'Ingresa tu correo electrónico';
|
||||
@override String get password_label => 'Contraseña';
|
||||
@override String get password_hint => 'Ingresa tu contraseña';
|
||||
@override String get forgot_password => '¿Olvidaste tu contraseña?';
|
||||
@override String get sign_in_button => 'Iniciar sesión';
|
||||
@override String get or_divider => 'o';
|
||||
@override String get social_apple => 'Iniciar sesión con Apple';
|
||||
@override String get social_google => 'Iniciar sesión con Google';
|
||||
@override String get no_account => '¿No tienes una cuenta? ';
|
||||
@override String get sign_up_link => 'Regístrate';
|
||||
}
|
||||
|
||||
// Path: client_authentication.sign_up_page
|
||||
class _TranslationsClientAuthenticationSignUpPageEs implements TranslationsClientAuthenticationSignUpPageEn {
|
||||
_TranslationsClientAuthenticationSignUpPageEs._(this._root);
|
||||
|
||||
final TranslationsEs _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override String get title => 'Crear cuenta';
|
||||
@override String get subtitle => 'Comienza con Krow para tu negocio';
|
||||
@override String get company_label => 'Nombre de la empresa';
|
||||
@override String get company_hint => 'Ingresa el nombre de la empresa';
|
||||
@override String get email_label => 'Correo electrónico';
|
||||
@override String get email_hint => 'Ingresa tu correo electrónico';
|
||||
@override String get password_label => 'Contraseña';
|
||||
@override String get password_hint => 'Crea una contraseña';
|
||||
@override String get confirm_password_label => 'Confirmar contraseña';
|
||||
@override String get confirm_password_hint => 'Confirma tu contraseña';
|
||||
@override String get create_account_button => 'Crear cuenta';
|
||||
@override String get or_divider => 'o';
|
||||
@override String get social_apple => 'Regístrate con Apple';
|
||||
@override String get social_google => 'Regístrate con Google';
|
||||
@override String get has_account => '¿Ya tienes una cuenta? ';
|
||||
@override String get sign_in_link => 'Iniciar sesión';
|
||||
}
|
||||
|
||||
// Path: client_home.dashboard
|
||||
class _TranslationsClientHomeDashboardEs implements TranslationsClientHomeDashboardEn {
|
||||
_TranslationsClientHomeDashboardEs._(this._root);
|
||||
|
||||
final TranslationsEs _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override String get welcome_back => 'Bienvenido de nuevo';
|
||||
@override String get edit_mode_active => 'Modo Edición Activo';
|
||||
@override String get drag_instruction => 'Arrastra para reordenar, cambia la visibilidad';
|
||||
@override String get reset => 'Restablecer';
|
||||
@override String get metric_needed => 'Necesario';
|
||||
@override String get metric_filled => 'Lleno';
|
||||
@override String get metric_open => 'Abierto';
|
||||
@override String get view_all => 'Ver todo';
|
||||
@override String insight_lightbulb({required Object amount}) => 'Ahorra ${amount}/mes';
|
||||
@override String get insight_tip => 'Reserva con 48h de antelación para mejores tarifas';
|
||||
}
|
||||
|
||||
// Path: client_home.widgets
|
||||
class _TranslationsClientHomeWidgetsEs implements TranslationsClientHomeWidgetsEn {
|
||||
_TranslationsClientHomeWidgetsEs._(this._root);
|
||||
|
||||
final TranslationsEs _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override String get actions => 'Acciones Rápidas';
|
||||
@override String get reorder => 'Reordenar';
|
||||
@override String get coverage => 'Cobertura de Hoy';
|
||||
@override String get spending => 'Información de Gastos';
|
||||
@override String get live_activity => 'Actividad en Vivo';
|
||||
}
|
||||
|
||||
// Path: client_home.actions
|
||||
class _TranslationsClientHomeActionsEs implements TranslationsClientHomeActionsEn {
|
||||
_TranslationsClientHomeActionsEs._(this._root);
|
||||
|
||||
final TranslationsEs _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override String get rapid => 'RÁPIDO';
|
||||
@override String get rapid_subtitle => 'Urgente mismo día';
|
||||
@override String get create_order => 'Crear Orden';
|
||||
@override String get create_order_subtitle => 'Programar turnos';
|
||||
}
|
||||
|
||||
// Path: client_home.reorder
|
||||
class _TranslationsClientHomeReorderEs implements TranslationsClientHomeReorderEn {
|
||||
_TranslationsClientHomeReorderEs._(this._root);
|
||||
|
||||
final TranslationsEs _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override String get title => 'REORDENAR';
|
||||
@override String get reorder_button => 'Reordenar';
|
||||
@override String per_hr({required Object amount}) => '${amount}/hr';
|
||||
}
|
||||
|
||||
// Path: client_home.form
|
||||
class _TranslationsClientHomeFormEs implements TranslationsClientHomeFormEn {
|
||||
_TranslationsClientHomeFormEs._(this._root);
|
||||
|
||||
final TranslationsEs _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override String get edit_reorder => 'Editar y Reordenar';
|
||||
@override String get post_new => 'Publicar un Nuevo Turno';
|
||||
@override String get review_subtitle => 'Revisa y edita los detalles antes de publicar';
|
||||
@override String get date_label => 'Fecha *';
|
||||
@override String get date_hint => 'mm/dd/aaaa';
|
||||
@override String get location_label => 'Ubicación *';
|
||||
@override String get location_hint => 'Dirección del negocio';
|
||||
@override String get positions_title => 'Posiciones';
|
||||
@override String get add_position => 'Añadir Posición';
|
||||
@override String get role_label => 'Rol *';
|
||||
@override String get role_hint => 'Seleccionar rol';
|
||||
@override String get start_time => 'Hora de Inicio *';
|
||||
@override String get end_time => 'Hora de Fin *';
|
||||
@override String get workers_needed => 'Trabajadores Necesarios *';
|
||||
@override String get hourly_rate => 'Tarifa por hora (\$) *';
|
||||
@override String get post_shift => 'Publicar Turno';
|
||||
}
|
||||
|
||||
// Path: staff_authentication.profile_setup_page.steps
|
||||
class _TranslationsStaffAuthenticationProfileSetupPageStepsEs implements TranslationsStaffAuthenticationProfileSetupPageStepsEn {
|
||||
_TranslationsStaffAuthenticationProfileSetupPageStepsEs._(this._root);
|
||||
|
||||
final TranslationsEs _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override String get basic => 'Información básica';
|
||||
@override String get location => 'Ubicación';
|
||||
@override String get experience => 'Experiencia';
|
||||
}
|
||||
|
||||
// Path: staff_authentication.profile_setup_page.basic_info
|
||||
class _TranslationsStaffAuthenticationProfileSetupPageBasicInfoEs implements TranslationsStaffAuthenticationProfileSetupPageBasicInfoEn {
|
||||
_TranslationsStaffAuthenticationProfileSetupPageBasicInfoEs._(this._root);
|
||||
|
||||
final TranslationsEs _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override String get title => 'Conozcámonos';
|
||||
@override String get subtitle => 'Cuéntanos un poco sobre ti';
|
||||
@override String get full_name_label => 'Nombre completo *';
|
||||
@override String get full_name_hint => 'Juan Pérez';
|
||||
@override String get bio_label => 'Biografía corta';
|
||||
@override String get bio_hint => 'Profesional experimentado en hostelería...';
|
||||
}
|
||||
|
||||
// Path: staff_authentication.profile_setup_page.location
|
||||
class _TranslationsStaffAuthenticationProfileSetupPageLocationEs implements TranslationsStaffAuthenticationProfileSetupPageLocationEn {
|
||||
_TranslationsStaffAuthenticationProfileSetupPageLocationEs._(this._root);
|
||||
|
||||
final TranslationsEs _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override String get title => '¿Dónde quieres trabajar?';
|
||||
@override String get subtitle => 'Agrega tus ubicaciones de trabajo preferidas';
|
||||
@override String get add_location_label => 'Agregar ubicación *';
|
||||
@override String get add_location_hint => 'Ciudad o código postal';
|
||||
@override String get add_button => 'Agregar';
|
||||
@override String max_distance({required Object distance}) => 'Distancia máxima: ${distance} millas';
|
||||
@override String get min_dist_label => '5 mi';
|
||||
@override String get max_dist_label => '50 mi';
|
||||
}
|
||||
|
||||
// Path: staff_authentication.profile_setup_page.experience
|
||||
class _TranslationsStaffAuthenticationProfileSetupPageExperienceEs implements TranslationsStaffAuthenticationProfileSetupPageExperienceEn {
|
||||
_TranslationsStaffAuthenticationProfileSetupPageExperienceEs._(this._root);
|
||||
|
||||
final TranslationsEs _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override String get title => '¿Cuáles son tus habilidades?';
|
||||
@override String get subtitle => 'Selecciona todas las que correspondan';
|
||||
@override String get skills_label => 'Habilidades *';
|
||||
@override String get industries_label => 'Industrias preferidas';
|
||||
@override late final _TranslationsStaffAuthenticationProfileSetupPageExperienceSkillsEs skills = _TranslationsStaffAuthenticationProfileSetupPageExperienceSkillsEs._(_root);
|
||||
@override late final _TranslationsStaffAuthenticationProfileSetupPageExperienceIndustriesEs industries = _TranslationsStaffAuthenticationProfileSetupPageExperienceIndustriesEs._(_root);
|
||||
}
|
||||
|
||||
// Path: staff_authentication.profile_setup_page.experience.skills
|
||||
class _TranslationsStaffAuthenticationProfileSetupPageExperienceSkillsEs implements TranslationsStaffAuthenticationProfileSetupPageExperienceSkillsEn {
|
||||
_TranslationsStaffAuthenticationProfileSetupPageExperienceSkillsEs._(this._root);
|
||||
|
||||
final TranslationsEs _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override String get food_service => 'Servicio de comida';
|
||||
@override String get bartending => 'Preparación de bebidas';
|
||||
@override String get warehouse => 'Almacén';
|
||||
@override String get retail => 'Venta minorista';
|
||||
@override String get events => 'Eventos';
|
||||
@override String get customer_service => 'Servicio al cliente';
|
||||
@override String get cleaning => 'Limpieza';
|
||||
@override String get security => 'Seguridad';
|
||||
@override String get driving => 'Conducción';
|
||||
@override String get cooking => 'Cocina';
|
||||
}
|
||||
|
||||
// Path: staff_authentication.profile_setup_page.experience.industries
|
||||
class _TranslationsStaffAuthenticationProfileSetupPageExperienceIndustriesEs implements TranslationsStaffAuthenticationProfileSetupPageExperienceIndustriesEn {
|
||||
_TranslationsStaffAuthenticationProfileSetupPageExperienceIndustriesEs._(this._root);
|
||||
|
||||
final TranslationsEs _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override String get hospitality => 'Hostelería';
|
||||
@override String get food_service => 'Servicio de comida';
|
||||
@override String get warehouse => 'Almacén';
|
||||
@override String get events => 'Eventos';
|
||||
@override String get retail => 'Venta minorista';
|
||||
@override String get healthcare => 'Atención médica';
|
||||
}
|
||||
|
||||
/// The flat map containing all translations for locale <es>.
|
||||
/// Only for edge cases! For simple maps, use the map function of this library.
|
||||
///
|
||||
/// The Dart AOT compiler has issues with very large switch statements,
|
||||
/// so the map is split into smaller functions (512 entries each).
|
||||
extension on TranslationsEs {
|
||||
dynamic _flatMapFunction(String path) {
|
||||
return switch (path) {
|
||||
'common.ok' => 'Aceptar',
|
||||
'common.cancel' => 'Cancelar',
|
||||
'common.save' => 'Guardar',
|
||||
'common.delete' => 'Eliminar',
|
||||
'common.continue_text' => 'Continuar',
|
||||
'settings.language' => 'Idioma',
|
||||
'settings.change_language' => 'Cambiar Idioma',
|
||||
'staff_authentication.get_started_page.title_part1' => 'Trabaja, Crece, ',
|
||||
'staff_authentication.get_started_page.title_part2' => 'Elévate',
|
||||
'staff_authentication.get_started_page.subtitle' => 'Construye tu carrera en hostelería con \nflexibilidad y libertad.',
|
||||
'staff_authentication.get_started_page.sign_up_button' => 'Registrarse',
|
||||
'staff_authentication.get_started_page.log_in_button' => 'Iniciar sesión',
|
||||
'staff_authentication.phone_verification_page.validation_error' => 'Por favor, ingresa un número de teléfono válido de 10 dígitos',
|
||||
'staff_authentication.phone_verification_page.send_code_button' => 'Enviar código',
|
||||
'staff_authentication.phone_verification_page.enter_code_title' => 'Ingresa el código de verificación',
|
||||
'staff_authentication.phone_verification_page.code_sent_message' => 'Enviamos un código de 6 dígitos a ',
|
||||
'staff_authentication.phone_verification_page.code_sent_instruction' => '. Ingrésalo a continuación para verificar tu cuenta.',
|
||||
'staff_authentication.phone_input.title' => 'Verifica tu número de teléfono',
|
||||
'staff_authentication.phone_input.subtitle' => 'Te enviaremos un código de verificación para comenzar.',
|
||||
'staff_authentication.phone_input.label' => 'Número de teléfono',
|
||||
'staff_authentication.phone_input.hint' => 'Ingresa tu número',
|
||||
'staff_authentication.otp_verification.did_not_get_code' => '¿No recibiste el código?',
|
||||
'staff_authentication.otp_verification.resend_in' => ({required Object seconds}) => 'Reenviar en ${seconds} s',
|
||||
'staff_authentication.otp_verification.resend_code' => 'Reenviar código',
|
||||
'staff_authentication.profile_setup_page.step_indicator' => ({required Object current, required Object total}) => 'Paso ${current} de ${total}',
|
||||
'staff_authentication.profile_setup_page.error_occurred' => 'Ocurrió un error',
|
||||
'staff_authentication.profile_setup_page.complete_setup_button' => 'Completar configuración',
|
||||
'staff_authentication.profile_setup_page.steps.basic' => 'Información básica',
|
||||
'staff_authentication.profile_setup_page.steps.location' => 'Ubicación',
|
||||
'staff_authentication.profile_setup_page.steps.experience' => 'Experiencia',
|
||||
'staff_authentication.profile_setup_page.basic_info.title' => 'Conozcámonos',
|
||||
'staff_authentication.profile_setup_page.basic_info.subtitle' => 'Cuéntanos un poco sobre ti',
|
||||
'staff_authentication.profile_setup_page.basic_info.full_name_label' => 'Nombre completo *',
|
||||
'staff_authentication.profile_setup_page.basic_info.full_name_hint' => 'Juan Pérez',
|
||||
'staff_authentication.profile_setup_page.basic_info.bio_label' => 'Biografía corta',
|
||||
'staff_authentication.profile_setup_page.basic_info.bio_hint' => 'Profesional experimentado en hostelería...',
|
||||
'staff_authentication.profile_setup_page.location.title' => '¿Dónde quieres trabajar?',
|
||||
'staff_authentication.profile_setup_page.location.subtitle' => 'Agrega tus ubicaciones de trabajo preferidas',
|
||||
'staff_authentication.profile_setup_page.location.add_location_label' => 'Agregar ubicación *',
|
||||
'staff_authentication.profile_setup_page.location.add_location_hint' => 'Ciudad o código postal',
|
||||
'staff_authentication.profile_setup_page.location.add_button' => 'Agregar',
|
||||
'staff_authentication.profile_setup_page.location.max_distance' => ({required Object distance}) => 'Distancia máxima: ${distance} millas',
|
||||
'staff_authentication.profile_setup_page.location.min_dist_label' => '5 mi',
|
||||
'staff_authentication.profile_setup_page.location.max_dist_label' => '50 mi',
|
||||
'staff_authentication.profile_setup_page.experience.title' => '¿Cuáles son tus habilidades?',
|
||||
'staff_authentication.profile_setup_page.experience.subtitle' => 'Selecciona todas las que correspondan',
|
||||
'staff_authentication.profile_setup_page.experience.skills_label' => 'Habilidades *',
|
||||
'staff_authentication.profile_setup_page.experience.industries_label' => 'Industrias preferidas',
|
||||
'staff_authentication.profile_setup_page.experience.skills.food_service' => 'Servicio de comida',
|
||||
'staff_authentication.profile_setup_page.experience.skills.bartending' => 'Preparación de bebidas',
|
||||
'staff_authentication.profile_setup_page.experience.skills.warehouse' => 'Almacén',
|
||||
'staff_authentication.profile_setup_page.experience.skills.retail' => 'Venta minorista',
|
||||
'staff_authentication.profile_setup_page.experience.skills.events' => 'Eventos',
|
||||
'staff_authentication.profile_setup_page.experience.skills.customer_service' => 'Servicio al cliente',
|
||||
'staff_authentication.profile_setup_page.experience.skills.cleaning' => 'Limpieza',
|
||||
'staff_authentication.profile_setup_page.experience.skills.security' => 'Seguridad',
|
||||
'staff_authentication.profile_setup_page.experience.skills.driving' => 'Conducción',
|
||||
'staff_authentication.profile_setup_page.experience.skills.cooking' => 'Cocina',
|
||||
'staff_authentication.profile_setup_page.experience.industries.hospitality' => 'Hostelería',
|
||||
'staff_authentication.profile_setup_page.experience.industries.food_service' => 'Servicio de comida',
|
||||
'staff_authentication.profile_setup_page.experience.industries.warehouse' => 'Almacén',
|
||||
'staff_authentication.profile_setup_page.experience.industries.events' => 'Eventos',
|
||||
'staff_authentication.profile_setup_page.experience.industries.retail' => 'Venta minorista',
|
||||
'staff_authentication.profile_setup_page.experience.industries.healthcare' => 'Atención médica',
|
||||
'staff_authentication.common.trouble_question' => '¿Tienes problemas? ',
|
||||
'staff_authentication.common.contact_support' => 'Contactar a soporte',
|
||||
'client_authentication.get_started_page.title' => 'Toma el control de tus\nturnos y eventos',
|
||||
'client_authentication.get_started_page.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',
|
||||
'client_authentication.get_started_page.sign_in_button' => 'Iniciar sesión',
|
||||
'client_authentication.get_started_page.create_account_button' => 'Crear cuenta',
|
||||
'client_authentication.sign_in_page.title' => 'Bienvenido de nuevo',
|
||||
'client_authentication.sign_in_page.subtitle' => 'Inicia sesión para gestionar tus turnos y trabajadores',
|
||||
'client_authentication.sign_in_page.email_label' => 'Correo electrónico',
|
||||
'client_authentication.sign_in_page.email_hint' => 'Ingresa tu correo electrónico',
|
||||
'client_authentication.sign_in_page.password_label' => 'Contraseña',
|
||||
'client_authentication.sign_in_page.password_hint' => 'Ingresa tu contraseña',
|
||||
'client_authentication.sign_in_page.forgot_password' => '¿Olvidaste tu contraseña?',
|
||||
'client_authentication.sign_in_page.sign_in_button' => 'Iniciar sesión',
|
||||
'client_authentication.sign_in_page.or_divider' => 'o',
|
||||
'client_authentication.sign_in_page.social_apple' => 'Iniciar sesión con Apple',
|
||||
'client_authentication.sign_in_page.social_google' => 'Iniciar sesión con Google',
|
||||
'client_authentication.sign_in_page.no_account' => '¿No tienes una cuenta? ',
|
||||
'client_authentication.sign_in_page.sign_up_link' => 'Regístrate',
|
||||
'client_authentication.sign_up_page.title' => 'Crear cuenta',
|
||||
'client_authentication.sign_up_page.subtitle' => 'Comienza con Krow para tu negocio',
|
||||
'client_authentication.sign_up_page.company_label' => 'Nombre de la empresa',
|
||||
'client_authentication.sign_up_page.company_hint' => 'Ingresa el nombre de la empresa',
|
||||
'client_authentication.sign_up_page.email_label' => 'Correo electrónico',
|
||||
'client_authentication.sign_up_page.email_hint' => 'Ingresa tu correo electrónico',
|
||||
'client_authentication.sign_up_page.password_label' => 'Contraseña',
|
||||
'client_authentication.sign_up_page.password_hint' => 'Crea una contraseña',
|
||||
'client_authentication.sign_up_page.confirm_password_label' => 'Confirmar contraseña',
|
||||
'client_authentication.sign_up_page.confirm_password_hint' => 'Confirma tu contraseña',
|
||||
'client_authentication.sign_up_page.create_account_button' => 'Crear cuenta',
|
||||
'client_authentication.sign_up_page.or_divider' => 'o',
|
||||
'client_authentication.sign_up_page.social_apple' => 'Regístrate con Apple',
|
||||
'client_authentication.sign_up_page.social_google' => 'Regístrate con Google',
|
||||
'client_authentication.sign_up_page.has_account' => '¿Ya tienes una cuenta? ',
|
||||
'client_authentication.sign_up_page.sign_in_link' => 'Iniciar sesión',
|
||||
'client_home.shift_created_success' => 'Orden de turno enviada con éxito',
|
||||
'client_home.dashboard.welcome_back' => 'Bienvenido de nuevo',
|
||||
'client_home.dashboard.edit_mode_active' => 'Modo Edición Activo',
|
||||
'client_home.dashboard.drag_instruction' => 'Arrastra para reordenar, cambia la visibilidad',
|
||||
'client_home.dashboard.reset' => 'Restablecer',
|
||||
'client_home.dashboard.metric_needed' => 'Necesario',
|
||||
'client_home.dashboard.metric_filled' => 'Lleno',
|
||||
'client_home.dashboard.metric_open' => 'Abierto',
|
||||
'client_home.dashboard.view_all' => 'Ver todo',
|
||||
'client_home.dashboard.insight_lightbulb' => ({required Object amount}) => 'Ahorra ${amount}/mes',
|
||||
'client_home.dashboard.insight_tip' => 'Reserva con 48h de antelación para mejores tarifas',
|
||||
'client_home.widgets.actions' => 'Acciones Rápidas',
|
||||
'client_home.widgets.reorder' => 'Reordenar',
|
||||
'client_home.widgets.coverage' => 'Cobertura de Hoy',
|
||||
'client_home.widgets.spending' => 'Información de Gastos',
|
||||
'client_home.widgets.live_activity' => 'Actividad en Vivo',
|
||||
'client_home.actions.rapid' => 'RÁPIDO',
|
||||
'client_home.actions.rapid_subtitle' => 'Urgente mismo día',
|
||||
'client_home.actions.create_order' => 'Crear Orden',
|
||||
'client_home.actions.create_order_subtitle' => 'Programar turnos',
|
||||
'client_home.reorder.title' => 'REORDENAR',
|
||||
'client_home.reorder.reorder_button' => 'Reordenar',
|
||||
'client_home.reorder.per_hr' => ({required Object amount}) => '${amount}/hr',
|
||||
'client_home.form.edit_reorder' => 'Editar y Reordenar',
|
||||
'client_home.form.post_new' => 'Publicar un Nuevo Turno',
|
||||
'client_home.form.review_subtitle' => 'Revisa y edita los detalles antes de publicar',
|
||||
'client_home.form.date_label' => 'Fecha *',
|
||||
'client_home.form.date_hint' => 'mm/dd/aaaa',
|
||||
'client_home.form.location_label' => 'Ubicación *',
|
||||
'client_home.form.location_hint' => 'Dirección del negocio',
|
||||
'client_home.form.positions_title' => 'Posiciones',
|
||||
'client_home.form.add_position' => 'Añadir Posición',
|
||||
'client_home.form.role_label' => 'Rol *',
|
||||
'client_home.form.role_hint' => 'Seleccionar rol',
|
||||
'client_home.form.start_time' => 'Hora de Inicio *',
|
||||
'client_home.form.end_time' => 'Hora de Fin *',
|
||||
'client_home.form.workers_needed' => 'Trabajadores Necesarios *',
|
||||
'client_home.form.hourly_rate' => 'Tarifa por hora (\$) *',
|
||||
'client_home.form.post_shift' => 'Publicar Turno',
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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>(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
38
apps/packages/core_localization/pubspec.yaml
Normal file
38
apps/packages/core_localization/pubspec.yaml
Normal 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
|
||||
12
apps/packages/core_localization/test/localization_test.dart
Normal file
12
apps/packages/core_localization/test/localization_test.dart
Normal 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);
|
||||
});
|
||||
}
|
||||
17
apps/packages/data_connect/lib/krow_data_connect.dart
Normal file
17
apps/packages/data_connect/lib/krow_data_connect.dart
Normal file
@@ -0,0 +1,17 @@
|
||||
/// The Data Connect layer.
|
||||
///
|
||||
/// This package provides mock implementations of domain repository interfaces
|
||||
/// for development and testing purposes.
|
||||
///
|
||||
/// TODO: These mocks currently do not implement any specific interfaces.
|
||||
/// They will implement interfaces defined in feature packages once those are created.
|
||||
|
||||
export 'src/mocks/auth_repository_mock.dart';
|
||||
export 'src/mocks/staff_repository_mock.dart';
|
||||
export 'src/mocks/business_repository_mock.dart';
|
||||
export 'src/mocks/event_repository_mock.dart';
|
||||
export 'src/mocks/skill_repository_mock.dart';
|
||||
export 'src/mocks/financial_repository_mock.dart';
|
||||
export 'src/mocks/rating_repository_mock.dart';
|
||||
export 'src/mocks/support_repository_mock.dart';
|
||||
export 'src/data_connect_module.dart';
|
||||
11
apps/packages/data_connect/lib/src/data_connect_module.dart
Normal file
11
apps/packages/data_connect/lib/src/data_connect_module.dart
Normal file
@@ -0,0 +1,11 @@
|
||||
import 'package:flutter_modular/flutter_modular.dart';
|
||||
import 'mocks/auth_repository_mock.dart';
|
||||
|
||||
/// A module that provides Data Connect dependencies, including mocks.
|
||||
class DataConnectModule extends Module {
|
||||
@override
|
||||
void exportedBinds(Injector i) {
|
||||
// Make the AuthRepositoryMock available to any module that imports this one.
|
||||
i.addLazySingleton(AuthRepositoryMock.new);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import 'package:krow_domain/krow_domain.dart';
|
||||
|
||||
// TODO: Implement AuthRepositoryInterface once defined in a feature package.
|
||||
class AuthRepositoryMock {
|
||||
Stream<User?> get currentUser => Stream.value(
|
||||
const User(id: 'mock_user_1', email: 'test@krow.com', role: 'staff'),
|
||||
);
|
||||
|
||||
Future<String?> signInWithPhone(String phoneNumber) async {
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
return 'mock_verification_id';
|
||||
}
|
||||
|
||||
Future<User?> verifyOtp(String verificationId, String smsCode) async {
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
return const User(id: 'mock_user_1', email: 'test@krow.com', role: 'staff');
|
||||
}
|
||||
|
||||
Future<void> signOut() async {
|
||||
await Future.delayed(const Duration(milliseconds: 200));
|
||||
}
|
||||
|
||||
/// Signs in a user with email and password (Mock).
|
||||
Future<User> signInWithEmail(String email, String password) async {
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
return User(id: 'mock_client_1', email: email, role: 'client_admin');
|
||||
}
|
||||
|
||||
/// Registers a new user with email and password (Mock).
|
||||
Future<User> signUpWithEmail(
|
||||
String email,
|
||||
String password,
|
||||
String companyName,
|
||||
) async {
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
return User(id: 'mock_client_new', email: email, role: 'client_admin');
|
||||
}
|
||||
|
||||
/// Authenticates using a social provider (Mock).
|
||||
Future<User> signInWithSocial(String provider) async {
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
return const User(
|
||||
id: 'mock_social_user',
|
||||
email: 'social@example.com',
|
||||
role: 'client_admin',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import 'package:krow_domain/krow_domain.dart';
|
||||
|
||||
// TODO: Implement BusinessRepositoryInterface once defined in a feature package.
|
||||
class BusinessRepositoryMock {
|
||||
Future<Business?> getBusiness(String id) async {
|
||||
await Future.delayed(const Duration(milliseconds: 300));
|
||||
return const Business(
|
||||
id: 'biz_1',
|
||||
name: 'Acme Events Ltd',
|
||||
registrationNumber: 'REG123456',
|
||||
status: BusinessStatus.active,
|
||||
avatar: 'https://via.placeholder.com/150',
|
||||
);
|
||||
}
|
||||
|
||||
Future<List<Hub>> getHubs(String businessId) async {
|
||||
await Future.delayed(const Duration(milliseconds: 300));
|
||||
return [
|
||||
const Hub(
|
||||
id: 'hub_1',
|
||||
businessId: 'biz_1',
|
||||
name: 'London HQ',
|
||||
address: '123 Oxford Street, London',
|
||||
status: HubStatus.active,
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
import 'package:krow_domain/krow_domain.dart';
|
||||
|
||||
// TODO: Implement EventRepositoryInterface once defined in a feature package.
|
||||
class EventRepositoryMock {
|
||||
Future<Assignment> applyForPosition(String positionId, String staffId) async {
|
||||
await Future.delayed(const Duration(milliseconds: 600));
|
||||
return Assignment(
|
||||
id: 'assign_1',
|
||||
positionId: positionId,
|
||||
staffId: staffId,
|
||||
status: AssignmentStatus.assigned,
|
||||
);
|
||||
}
|
||||
|
||||
Future<Event?> getEvent(String id) async {
|
||||
await Future.delayed(const Duration(milliseconds: 300));
|
||||
return _mockEvent;
|
||||
}
|
||||
|
||||
Future<List<EventShift>> getEventShifts(String eventId) async {
|
||||
await Future.delayed(const Duration(milliseconds: 300));
|
||||
return [
|
||||
const EventShift(
|
||||
id: 'shift_1',
|
||||
eventId: 'event_1',
|
||||
name: 'Morning Setup',
|
||||
address: 'Hyde Park, London',
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
Future<List<Assignment>> getStaffAssignments(String staffId) async {
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
return [
|
||||
const Assignment(
|
||||
id: 'assign_1',
|
||||
positionId: 'pos_1',
|
||||
staffId: 'staff_1',
|
||||
status: AssignmentStatus.confirmed,
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
Future<List<Event>> getUpcomingEvents() async {
|
||||
await Future.delayed(const Duration(milliseconds: 800));
|
||||
return [_mockEvent];
|
||||
}
|
||||
|
||||
static final _mockEvent = Event(
|
||||
id: 'event_1',
|
||||
businessId: 'biz_1',
|
||||
hubId: 'hub_1',
|
||||
name: 'Summer Festival 2026',
|
||||
date: DateTime.now().add(const Duration(days: 10)),
|
||||
status: EventStatus.active,
|
||||
contractType: 'freelance',
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import 'package:krow_domain/krow_domain.dart';
|
||||
|
||||
// TODO: Implement FinancialRepositoryInterface once defined in a feature package.
|
||||
class FinancialRepositoryMock {
|
||||
Future<List<Invoice>> getInvoices(String businessId) async {
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
return [
|
||||
const Invoice(
|
||||
id: 'inv_1',
|
||||
eventId: 'event_1',
|
||||
businessId: 'biz_1',
|
||||
status: InvoiceStatus.paid,
|
||||
totalAmount: 1500.0,
|
||||
workAmount: 1400.0,
|
||||
addonsAmount: 100.0,
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
Future<List<StaffPayment>> getStaffPayments(String staffId) async {
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
return [
|
||||
StaffPayment(
|
||||
id: 'pay_1',
|
||||
staffId: staffId,
|
||||
assignmentId: 'assign_1',
|
||||
amount: 120.0,
|
||||
status: PaymentStatus.paid,
|
||||
paidAt: DateTime.now().subtract(const Duration(days: 2)),
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import 'package:krow_domain/krow_domain.dart';
|
||||
|
||||
// TODO: Implement RatingRepositoryInterface once defined in a feature package.
|
||||
class RatingRepositoryMock {
|
||||
Future<List<StaffRating>> getStaffRatings(String staffId) async {
|
||||
await Future.delayed(const Duration(milliseconds: 400));
|
||||
return [
|
||||
const StaffRating(
|
||||
id: 'rate_1',
|
||||
staffId: 'staff_1',
|
||||
eventId: 'event_1',
|
||||
businessId: 'biz_1',
|
||||
rating: 5,
|
||||
comment: 'Great work!',
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
Future<void> submitRating(StaffRating rating) async {
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import 'package:krow_domain/krow_domain.dart';
|
||||
|
||||
// TODO: Implement SkillRepositoryInterface once defined in a feature package.
|
||||
class SkillRepositoryMock {
|
||||
Future<void> addStaffSkill(StaffSkill skill) async {
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
}
|
||||
|
||||
Future<List<Skill>> getAllSkills() async {
|
||||
await Future.delayed(const Duration(milliseconds: 300));
|
||||
return [
|
||||
const Skill(
|
||||
id: 'skill_1',
|
||||
categoryId: 'cat_1',
|
||||
name: 'Bartender',
|
||||
basePrice: 15.0,
|
||||
),
|
||||
const Skill(
|
||||
id: 'skill_2',
|
||||
categoryId: 'cat_2',
|
||||
name: 'Security Guard',
|
||||
basePrice: 18.0,
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
Future<List<StaffSkill>> getStaffSkills(String staffId) async {
|
||||
await Future.delayed(const Duration(milliseconds: 400));
|
||||
return [
|
||||
const StaffSkill(
|
||||
id: 'staff_skill_1',
|
||||
staffId: 'staff_1',
|
||||
skillId: 'skill_1',
|
||||
level: SkillLevel.skilled,
|
||||
experienceYears: 3,
|
||||
status: StaffSkillStatus.verified,
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import 'package:krow_domain/krow_domain.dart';
|
||||
|
||||
// TODO: Implement StaffRepositoryInterface once defined in a feature package.
|
||||
class StaffRepositoryMock {
|
||||
Future<Staff> createStaffProfile(Staff staff) async {
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
return staff;
|
||||
}
|
||||
|
||||
Future<List<Membership>> getMemberships(String userId) async {
|
||||
await Future.delayed(const Duration(milliseconds: 300));
|
||||
return [
|
||||
Membership(
|
||||
id: 'mem_1',
|
||||
userId: userId,
|
||||
memberableId: 'biz_1',
|
||||
memberableType: 'business',
|
||||
role: 'staff',
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
Future<Staff?> getStaffProfile(String userId) async {
|
||||
await Future.delayed(const Duration(milliseconds: 400));
|
||||
return Staff(
|
||||
id: 'staff_1',
|
||||
authProviderId: userId,
|
||||
name: 'John Doe',
|
||||
email: 'john@krow.com',
|
||||
status: StaffStatus.active,
|
||||
avatar: 'https://i.pravatar.cc/300',
|
||||
);
|
||||
}
|
||||
|
||||
Future<Staff> updateStaffProfile(Staff staff) async {
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
return staff;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import 'package:krow_domain/krow_domain.dart';
|
||||
|
||||
// TODO: Implement SupportRepositoryInterface once defined in a feature package.
|
||||
class SupportRepositoryMock {
|
||||
Future<List<Tag>> getTags() async {
|
||||
await Future.delayed(const Duration(milliseconds: 200));
|
||||
return [
|
||||
const Tag(id: 'tag_1', label: 'Urgent'),
|
||||
const Tag(id: 'tag_2', label: 'VIP Event'),
|
||||
];
|
||||
}
|
||||
|
||||
Future<List<WorkingArea>> getWorkingAreas() async {
|
||||
await Future.delayed(const Duration(milliseconds: 200));
|
||||
return [
|
||||
const WorkingArea(
|
||||
id: 'area_1',
|
||||
name: 'Central London',
|
||||
centerLat: 51.5074,
|
||||
centerLng: -0.1278,
|
||||
radiusKm: 10.0,
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
||||
16
apps/packages/data_connect/pubspec.yaml
Normal file
16
apps/packages/data_connect/pubspec.yaml
Normal file
@@ -0,0 +1,16 @@
|
||||
name: krow_data_connect
|
||||
description: Firebase Data Connect access layer.
|
||||
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_domain:
|
||||
path: ../domain
|
||||
flutter_modular: ^6.3.0
|
||||
31
apps/packages/design_system/.gitignore
vendored
Normal file
31
apps/packages/design_system/.gitignore
vendored
Normal 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/
|
||||
10
apps/packages/design_system/.metadata
Normal file
10
apps/packages/design_system/.metadata
Normal 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
|
||||
3
apps/packages/design_system/CHANGELOG.md
Normal file
3
apps/packages/design_system/CHANGELOG.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.0.1
|
||||
|
||||
* TODO: Describe initial release.
|
||||
1
apps/packages/design_system/LICENSE
Normal file
1
apps/packages/design_system/LICENSE
Normal file
@@ -0,0 +1 @@
|
||||
TODO: Add your license here.
|
||||
39
apps/packages/design_system/README.md
Normal file
39
apps/packages/design_system/README.md
Normal file
@@ -0,0 +1,39 @@
|
||||
<!--
|
||||
This README describes the package. If you publish this package to pub.dev,
|
||||
this README's contents appear on the landing page for your package.
|
||||
|
||||
For information about how to write a good package README, see the guide for
|
||||
[writing package pages](https://dart.dev/tools/pub/writing-package-pages).
|
||||
|
||||
For general information about developing packages, see the Dart guide for
|
||||
[creating packages](https://dart.dev/guides/libraries/create-packages)
|
||||
and the Flutter guide for
|
||||
[developing packages and plugins](https://flutter.dev/to/develop-packages).
|
||||
-->
|
||||
|
||||
TODO: Put a short description of the package here that helps potential users
|
||||
know whether this package might be useful for them.
|
||||
|
||||
## Features
|
||||
|
||||
TODO: List what your package can do. Maybe include images, gifs, or videos.
|
||||
|
||||
## Getting started
|
||||
|
||||
TODO: List prerequisites and provide or point to information on how to
|
||||
start using the package.
|
||||
|
||||
## Usage
|
||||
|
||||
TODO: Include short and useful examples for package users. Add longer examples
|
||||
to `/example` folder.
|
||||
|
||||
```dart
|
||||
const like = 'sample';
|
||||
```
|
||||
|
||||
## Additional information
|
||||
|
||||
TODO: Tell users more about the package: where to find more information, how to
|
||||
contribute to the package, how to file issues, what response they can expect
|
||||
from the package authors, and more.
|
||||
1
apps/packages/design_system/analysis_options.yaml
Normal file
1
apps/packages/design_system/analysis_options.yaml
Normal file
@@ -0,0 +1 @@
|
||||
include: ../../analytics_options.yaml
|
||||
BIN
apps/packages/design_system/assets/logo-blue.png
Normal file
BIN
apps/packages/design_system/assets/logo-blue.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 68 KiB |
BIN
apps/packages/design_system/assets/logo-yellow.png
Normal file
BIN
apps/packages/design_system/assets/logo-yellow.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 46 KiB |
12
apps/packages/design_system/lib/design_system.dart
Normal file
12
apps/packages/design_system/lib/design_system.dart
Normal file
@@ -0,0 +1,12 @@
|
||||
export 'src/ui_colors.dart';
|
||||
export 'src/ui_typography.dart';
|
||||
export 'src/ui_constants.dart';
|
||||
export 'src/ui_theme.dart';
|
||||
export 'src/ui_icons.dart';
|
||||
export 'src/ui_images_assets.dart';
|
||||
export 'src/widgets/ui_app_bar.dart';
|
||||
export 'src/widgets/ui_text_field.dart';
|
||||
export 'src/widgets/ui_step_indicator.dart';
|
||||
export 'src/widgets/ui_icon_button.dart';
|
||||
export 'src/widgets/ui_button.dart';
|
||||
export 'src/widgets/ui_chip.dart';
|
||||
322
apps/packages/design_system/lib/src/ui_colors.dart
Normal file
322
apps/packages/design_system/lib/src/ui_colors.dart
Normal file
@@ -0,0 +1,322 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// Static definitions of color palettes and semantic colors for the Staff Design System.
|
||||
/// Values are defined in design_tokens_react.md.
|
||||
class UiColors {
|
||||
UiColors._();
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 1. Base Tokens
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// Background color (#FAFBFC)
|
||||
static const Color background = Color(0xFFFAFBFC);
|
||||
|
||||
/// Foreground color (#121826)
|
||||
static const Color foreground = Color(0xFF121826);
|
||||
|
||||
/// Primary brand color blue (#0A39DF)
|
||||
static const Color primary = Color(0xFF0A39DF);
|
||||
|
||||
/// Foreground color on primary background (#F7FAFC)
|
||||
static const Color primaryForeground = Color(0xFFF7FAFC);
|
||||
|
||||
/// Inverse primary color (#9FABF1)
|
||||
static const Color primaryInverse = Color(0xFF9FABF1);
|
||||
|
||||
/// Secondary background color (#F1F3F5)
|
||||
static const Color secondary = Color(0xFFF1F3F5);
|
||||
|
||||
/// Foreground color on secondary background (#121826)
|
||||
static const Color secondaryForeground = Color(0xFF121826);
|
||||
|
||||
/// Muted background color (#F1F3F5)
|
||||
static const Color muted = Color(0xFFF1F3F5);
|
||||
|
||||
/// Muted foreground color (#6A7382)
|
||||
static const Color mutedForeground = Color(0xFF6A7382);
|
||||
|
||||
/// Accent yellow color (#F9E547)
|
||||
static const Color accent = Color(0xFFF9E547);
|
||||
|
||||
/// Foreground color on accent background (#4C460D)
|
||||
static const Color accentForeground = Color(0xFF4C460D);
|
||||
|
||||
/// Destructive red color (#F04444)
|
||||
static const Color destructive = Color(0xFFF04444);
|
||||
|
||||
/// Foreground color on destructive background (#FAFAFA)
|
||||
static const Color destructiveForeground = Color(0xFFFAFAFA);
|
||||
|
||||
/// Default border color (#D1D5DB)
|
||||
static const Color border = Color(0xFFD1D5DB);
|
||||
|
||||
/// Default input border color (#E7EAEE)
|
||||
static const Color input = Color(0xFFF5F6F8);
|
||||
|
||||
/// Focus ring color (#0A39DF)
|
||||
static const Color ring = Color(0xFF0A39DF);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 2. Semantic Mappings
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// --- Background Colors ---
|
||||
|
||||
/// Primary background (#FAFBFC)
|
||||
static const Color bgPrimary = background;
|
||||
|
||||
/// Secondary background (#F1F3F5)
|
||||
static const Color bgSecondary = secondary;
|
||||
|
||||
/// Tertiary background (#EDF0F2)
|
||||
static const Color bgThird = Color(0xFFEDF0F2);
|
||||
|
||||
/// Popup background (#FFFFFF)
|
||||
static const Color bgPopup = Color(0xFFFFFFFF);
|
||||
|
||||
/// Highlighted background (#FEF9C3)
|
||||
static const Color bgHighlight = Color(0xFFFEF9C3);
|
||||
|
||||
/// Menu background (#F8FAFC)
|
||||
static const Color bgMenu = Color(0xFFF8FAFC);
|
||||
|
||||
/// Banner background (#FFFFFF)
|
||||
static const Color bgBanner = Color(0xFFFFFFFF);
|
||||
|
||||
/// Overlay background (#000000 with 50% opacity)
|
||||
static const Color bgOverlay = Color(0x80000000);
|
||||
|
||||
/// Toast background (#121826)
|
||||
static const Color toastBg = Color(0xFF121826);
|
||||
|
||||
/// Input field background (#E3E6E9)
|
||||
static const Color bgInputField = input;
|
||||
|
||||
/// Footer banner background (#F1F5F9)
|
||||
static const Color bgFooterBanner = Color(0xFFF1F5F9);
|
||||
|
||||
// --- Text Colors ---
|
||||
|
||||
/// Primary text (#121826)
|
||||
static const Color textPrimary = foreground;
|
||||
|
||||
/// Secondary text (#6A7382)
|
||||
static const Color textSecondary = mutedForeground;
|
||||
|
||||
/// Inactive text (#9CA3AF)
|
||||
static const Color textInactive = Color(0xFF9CA3AF);
|
||||
|
||||
/// Placeholder text (#9CA3AF)
|
||||
static const Color textPlaceholder = Color(0xFF9CA3AF);
|
||||
|
||||
/// Description text (#6A7382)
|
||||
static const Color textDescription = mutedForeground;
|
||||
|
||||
/// Success text (#10B981)
|
||||
static const Color textSuccess = Color(0xFF10B981);
|
||||
|
||||
/// Error text (#F04444)
|
||||
static const Color textError = destructive;
|
||||
|
||||
/// Deep error text for containers (#450A0A)
|
||||
static const Color textErrorContainer = Color(0xFF450A0A);
|
||||
|
||||
/// Warning text (#D97706)
|
||||
static const Color textWarning = Color(0xFFD97706);
|
||||
|
||||
/// Link text (#0A39DF)
|
||||
static const Color textLink = primary;
|
||||
|
||||
/// Filter text (#4B5563)
|
||||
static const Color textFilter = Color(0xFF4B5563);
|
||||
|
||||
// --- Icon Colors ---
|
||||
|
||||
/// Primary icon (#121826)
|
||||
static const Color iconPrimary = foreground;
|
||||
|
||||
/// Secondary icon (#6A7382)
|
||||
static const Color iconSecondary = mutedForeground;
|
||||
|
||||
/// Tertiary icon (#9CA3AF)
|
||||
static const Color iconThird = Color(0xFF9CA3AF);
|
||||
|
||||
/// Inactive icon (#D1D5DB)
|
||||
static const Color iconInactive = Color(0xFFD1D5DB);
|
||||
|
||||
/// Active icon (#0A39DF)
|
||||
static const Color iconActive = primary;
|
||||
|
||||
/// Success icon (#10B981)
|
||||
static const Color iconSuccess = Color(0xFF10B981);
|
||||
|
||||
/// Error icon (#F04444)
|
||||
static const Color iconError = destructive;
|
||||
|
||||
// --- Loader Colors ---
|
||||
|
||||
/// Active loader (#0A39DF)
|
||||
static const Color loaderActive = primary;
|
||||
|
||||
/// Inactive loader (#E2E8F0)
|
||||
static const Color loaderInactive = Color(0xFFE2E8F0);
|
||||
|
||||
// --- Pin Input Colors ---
|
||||
|
||||
/// Unfilled pin (#E2E8F0)
|
||||
static const Color pinUnfilled = Color(0xFFE2E8F0);
|
||||
|
||||
/// Active pin (#0A39DF)
|
||||
static const Color pinActive = primary;
|
||||
|
||||
/// Inactive pin (#94A3B8)
|
||||
static const Color pinInactive = Color(0xFF94A3B8);
|
||||
|
||||
// --- Separator Colors ---
|
||||
|
||||
/// Primary separator (#E3E6E9)
|
||||
static const Color separatorPrimary = border;
|
||||
|
||||
/// Secondary separator (#F1F5F9)
|
||||
static const Color separatorSecondary = Color(0xFFF1F5F9);
|
||||
|
||||
/// Special separator (#F9E547)
|
||||
static const Color separatorSpecial = accent;
|
||||
|
||||
// --- Tag Colors ---
|
||||
|
||||
/// Default tag background (#F1F5F9)
|
||||
static const Color tagValue = Color(0xFFF1F5F9);
|
||||
|
||||
/// Pending state tag background (#FEF3C7)
|
||||
static const Color tagPending = Color(0xFFFEF3C7);
|
||||
|
||||
/// In-progress state tag background (#DBEAFE)
|
||||
static const Color tagInProgress = Color(0xFFDBEAFE);
|
||||
|
||||
/// Error state tag background (#FEE2E2)
|
||||
static const Color tagError = Color(0xFFFEE2E2);
|
||||
|
||||
/// Active state tag background (#DCFCE7)
|
||||
static const Color tagActive = Color(0xFFDCFCE7);
|
||||
|
||||
/// Frozen state tag background (#F3F4F6)
|
||||
static const Color tagFreeze = Color(0xFFF3F4F6);
|
||||
|
||||
/// Success state tag background (#DCFCE7)
|
||||
static const Color tagSuccess = Color(0xFFDCFCE7);
|
||||
|
||||
/// Refunded state tag background (#E0E7FF)
|
||||
static const Color tagRefunded = Color(0xFFE0E7FF);
|
||||
|
||||
// --- Border Colors ---
|
||||
|
||||
/// Static border (#D1D5DB)
|
||||
static const Color borderStill = border;
|
||||
|
||||
/// Primary border (#D1D5DB)
|
||||
static const Color borderPrimary = border;
|
||||
|
||||
/// Error border (#F04444)
|
||||
static const Color borderError = destructive;
|
||||
|
||||
/// Focus border (#0A39DF)
|
||||
static const Color borderFocus = ring;
|
||||
|
||||
/// Inactive border (#F1F5F9)
|
||||
static const Color borderInactive = Color(0xFFF1F5F9);
|
||||
|
||||
// --- Button Colors ---
|
||||
|
||||
/// Primary button default (#0A39DF)
|
||||
static const Color buttonPrimaryStill = primary;
|
||||
|
||||
/// Primary button hover (#082EB2)
|
||||
static const Color buttonPrimaryHover = Color(0xFF082EB2);
|
||||
|
||||
/// Primary button inactive (#F1F3F5)
|
||||
static const Color buttonPrimaryInactive = secondary;
|
||||
|
||||
/// Secondary button default (#F1F3F5)
|
||||
static const Color buttonSecondaryStill = secondary;
|
||||
|
||||
/// Secondary button hover (#E2E8F0)
|
||||
static const Color buttonSecondaryHover = Color(0xFFE2E8F0);
|
||||
|
||||
/// Secondary button inactive (#F3F4F6)
|
||||
static const Color buttonSecondaryInactive = Color(0xFFF3F4F6);
|
||||
|
||||
/// Button inactive state (#94A3B8)
|
||||
static const Color buttonInactive = Color(0xFF94A3B8);
|
||||
|
||||
/// Pin button background (#F8FAFC)
|
||||
static const Color pinButtonBackground = Color(0xFFF8FAFC);
|
||||
|
||||
// --- Switch Colors ---
|
||||
|
||||
/// Switch active state (#10B981)
|
||||
static const Color switchActive = Color(0xFF10B981);
|
||||
|
||||
/// Switch inactive state (#CBD5E1)
|
||||
static const Color switchInactive = Color(0xFFCBD5E1);
|
||||
|
||||
/// Switch dot inactive state (#FFFFFF)
|
||||
static const Color dotInactive = Color(0xFFFFFFFF);
|
||||
|
||||
// --- Basic Colors ---
|
||||
|
||||
/// Standard white (#FFFFFF)
|
||||
static const Color white = Color(0xFFFFFFFF);
|
||||
|
||||
/// Standard black (#000000)
|
||||
static const Color black = Color(0xFF000000);
|
||||
|
||||
/// Transparent color (0x00000000)
|
||||
static const Color transparent = Color(0x00000000);
|
||||
|
||||
/// Card background (#FFFFFF)
|
||||
static const Color cardViewBackground = Color(0xFFFFFFFF);
|
||||
|
||||
// --- Shadows ---
|
||||
|
||||
/// Primary popup shadow (#000000 with 10% opacity)
|
||||
static const Color popupShadow = Color(0x1A000000);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 3. ColorScheme
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// Generates a ColorScheme based on the tokens.
|
||||
static ColorScheme get colorScheme => const ColorScheme(
|
||||
brightness: Brightness.light,
|
||||
primary: primary,
|
||||
onPrimary: primaryForeground,
|
||||
primaryContainer: tagRefunded,
|
||||
onPrimaryContainer: primary,
|
||||
secondary: secondary,
|
||||
onSecondary: secondaryForeground,
|
||||
secondaryContainer: muted,
|
||||
onSecondaryContainer: secondaryForeground,
|
||||
tertiary: accent,
|
||||
onTertiary: accentForeground,
|
||||
tertiaryContainer: bgHighlight,
|
||||
onTertiaryContainer: accentForeground,
|
||||
error: destructive,
|
||||
onError: destructiveForeground,
|
||||
errorContainer: tagError,
|
||||
onErrorContainer: textErrorContainer,
|
||||
surface: background,
|
||||
onSurface: foreground,
|
||||
surfaceContainerHighest: muted,
|
||||
onSurfaceVariant: mutedForeground,
|
||||
outline: border,
|
||||
outlineVariant: separatorSecondary,
|
||||
shadow: black,
|
||||
scrim: black,
|
||||
inverseSurface: foreground,
|
||||
onInverseSurface: background,
|
||||
inversePrimary: primaryInverse,
|
||||
surfaceTint: primary,
|
||||
);
|
||||
}
|
||||
38
apps/packages/design_system/lib/src/ui_constants.dart
Normal file
38
apps/packages/design_system/lib/src/ui_constants.dart
Normal file
@@ -0,0 +1,38 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// Design system constants for spacing, radii, and other layout properties.
|
||||
class UiConstants {
|
||||
UiConstants._();
|
||||
|
||||
// --- Border Radii ---
|
||||
|
||||
/// Base radius: 12px
|
||||
static const double radiusBase = 12.0;
|
||||
static final BorderRadius radiusLg = BorderRadius.circular(radiusBase);
|
||||
|
||||
/// Medium radius: 6px
|
||||
static const double radiusMdValue = 6.0;
|
||||
static final BorderRadius radiusMd = BorderRadius.circular(radiusMdValue);
|
||||
|
||||
/// Small radius: 4px
|
||||
static final BorderRadius radiusSm = BorderRadius.circular(4.0);
|
||||
|
||||
/// Extra small radius: 2px
|
||||
static final BorderRadius radiusXs = BorderRadius.circular(2.0);
|
||||
|
||||
/// Large/Full radius
|
||||
static final BorderRadius radiusFull = BorderRadius.circular(999.0);
|
||||
|
||||
// --- Spacing ---
|
||||
|
||||
static const double space0 = 0.0;
|
||||
static const double space1 = 4.0;
|
||||
static const double space2 = 8.0;
|
||||
static const double space3 = 12.0;
|
||||
static const double space4 = 16.0;
|
||||
static const double space5 = 20.0;
|
||||
static const double space6 = 24.0;
|
||||
static const double space8 = 32.0;
|
||||
static const double space10 = 40.0;
|
||||
static const double space12 = 48.0;
|
||||
}
|
||||
174
apps/packages/design_system/lib/src/ui_icons.dart
Normal file
174
apps/packages/design_system/lib/src/ui_icons.dart
Normal file
@@ -0,0 +1,174 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:lucide_icons/lucide_icons.dart';
|
||||
|
||||
/// The primary icon library used by the design system.
|
||||
/// This allows for easier swapping of icon libraries in the future.
|
||||
typedef _IconLib = LucideIcons;
|
||||
|
||||
/// The secondary icon library used by the design system.
|
||||
/// This allows for easier swapping of icon libraries in the future.
|
||||
typedef _IconLib2 = FontAwesomeIcons;
|
||||
|
||||
/// Static definitions of icons for the UI design system.
|
||||
/// This class wraps the primary icon library to provide a consistent interface.
|
||||
///
|
||||
/// example:
|
||||
/// ```dart
|
||||
/// Icon(UiIcons.home)
|
||||
/// ```
|
||||
class UiIcons {
|
||||
UiIcons._();
|
||||
|
||||
// --- Navigation ---
|
||||
|
||||
/// Home icon
|
||||
static const IconData home = _IconLib.home;
|
||||
|
||||
/// Calendar icon for shifts or schedules
|
||||
static const IconData calendar = _IconLib.calendar;
|
||||
|
||||
/// Briefcase icon for jobs
|
||||
static const IconData briefcase = _IconLib.briefcase;
|
||||
|
||||
/// User icon for profile
|
||||
static const IconData user = _IconLib.user;
|
||||
|
||||
/// Settings icon
|
||||
static const IconData settings = _IconLib.settings;
|
||||
|
||||
// --- Actions ---
|
||||
|
||||
/// Search icon
|
||||
static const IconData search = _IconLib.search;
|
||||
|
||||
/// Filter icon
|
||||
static const IconData filter = _IconLib.filter;
|
||||
|
||||
/// Plus/Add icon
|
||||
static const IconData add = _IconLib.plus;
|
||||
|
||||
/// Edit icon
|
||||
static const IconData edit = _IconLib.edit2;
|
||||
|
||||
/// Delete/Trash icon
|
||||
static const IconData delete = _IconLib.trash2;
|
||||
|
||||
/// Checkmark icon
|
||||
static const IconData check = _IconLib.check;
|
||||
|
||||
/// X/Cancel icon
|
||||
static const IconData close = _IconLib.x;
|
||||
|
||||
/// Arrow right icon
|
||||
static const IconData arrowRight = _IconLib.arrowRight;
|
||||
|
||||
/// Arrow left icon
|
||||
static const IconData arrowLeft = _IconLib.arrowLeft;
|
||||
|
||||
/// Swap/Transfer icon
|
||||
static const IconData swap = _IconLib.arrowLeftRight;
|
||||
|
||||
/// Chevron right icon
|
||||
static const IconData chevronRight = _IconLib.chevronRight;
|
||||
|
||||
/// Chevron left icon
|
||||
static const IconData chevronLeft = _IconLib.chevronLeft;
|
||||
|
||||
// --- Status & Feedback ---
|
||||
|
||||
/// Info icon
|
||||
static const IconData info = _IconLib.info;
|
||||
|
||||
/// Help/Circle icon
|
||||
static const IconData help = _IconLib.helpCircle;
|
||||
|
||||
/// Alert/Triangle icon for warnings
|
||||
static const IconData warning = _IconLib.alertTriangle;
|
||||
|
||||
/// Alert/Circle icon for errors
|
||||
static const IconData error = _IconLib.alertCircle;
|
||||
|
||||
/// Success/Check circle icon
|
||||
static const IconData success = _IconLib.checkCircle2;
|
||||
|
||||
// --- Miscellaneous ---
|
||||
|
||||
/// Clock icon
|
||||
static const IconData clock = _IconLib.clock;
|
||||
|
||||
/// Log in icon
|
||||
static const IconData logIn = _IconLib.logIn;
|
||||
|
||||
/// Break icon (Coffee)
|
||||
static const IconData breakIcon = _IconLib.coffee;
|
||||
|
||||
/// Map pin icon for locations
|
||||
static const IconData mapPin = _IconLib.mapPin;
|
||||
|
||||
/// Dollar sign icon for payments/earnings
|
||||
static const IconData dollar = _IconLib.dollarSign;
|
||||
|
||||
/// Wallet icon
|
||||
static const IconData wallet = _IconLib.wallet;
|
||||
|
||||
/// Credit card icon
|
||||
static const IconData creditCard = _IconLib.creditCard;
|
||||
|
||||
/// Bell icon for notifications
|
||||
static const IconData bell = _IconLib.bell;
|
||||
|
||||
/// Log out icon
|
||||
static const IconData logOut = _IconLib.logOut;
|
||||
|
||||
/// File/Document icon
|
||||
static const IconData file = _IconLib.fileText;
|
||||
|
||||
/// Lock icon
|
||||
static const IconData lock = _IconLib.lock;
|
||||
|
||||
/// Shield check icon for compliance/security
|
||||
static const IconData shield = _IconLib.shieldCheck;
|
||||
|
||||
/// Sparkles icon for features or AI
|
||||
static const IconData sparkles = _IconLib.sparkles;
|
||||
|
||||
/// Star icon for ratings
|
||||
static const IconData star = _IconLib.star;
|
||||
|
||||
/// Camera icon for photo upload
|
||||
static const IconData camera = _IconLib.camera;
|
||||
|
||||
/// Mail icon
|
||||
static const IconData mail = _IconLib.mail;
|
||||
|
||||
/// Eye icon for visibility
|
||||
static const IconData eye = _IconLib.eye;
|
||||
|
||||
/// Eye off icon for hidden visibility
|
||||
static const IconData eyeOff = _IconLib.eyeOff;
|
||||
|
||||
/// Building icon for companies
|
||||
static const IconData building = _IconLib.building2;
|
||||
|
||||
/// Zap icon for rapid actions
|
||||
static const IconData zap = _IconLib.zap;
|
||||
|
||||
/// Grip vertical icon for reordering
|
||||
static const IconData gripVertical = _IconLib.gripVertical;
|
||||
|
||||
/// Trending down icon for insights
|
||||
static const IconData trendingDown = _IconLib.trendingDown;
|
||||
|
||||
/// Target icon for metrics
|
||||
static const IconData target = _IconLib.target;
|
||||
|
||||
/// Rotate CCW icon for reordering
|
||||
static const IconData rotateCcw = _IconLib.rotateCcw;
|
||||
|
||||
/// Apple icon
|
||||
static const IconData apple = _IconLib2.apple;
|
||||
|
||||
/// Google icon
|
||||
static const IconData google = _IconLib2.google;
|
||||
}
|
||||
14
apps/packages/design_system/lib/src/ui_images_assets.dart
Normal file
14
apps/packages/design_system/lib/src/ui_images_assets.dart
Normal file
@@ -0,0 +1,14 @@
|
||||
/// Static definitions of image asset paths for the Design System.
|
||||
///
|
||||
/// This class provides a centralized way to access image assets
|
||||
/// stored within the `design_system` package.
|
||||
class UiImageAssets {
|
||||
UiImageAssets._();
|
||||
|
||||
/// The path to the yellow version of the logo image.
|
||||
static const String logoYellow =
|
||||
'packages/design_system/assets/logo-yellow.png';
|
||||
|
||||
/// The path to the blue version of the logo image.
|
||||
static const String logoBlue = 'packages/design_system/assets/logo-blue.png';
|
||||
}
|
||||
359
apps/packages/design_system/lib/src/ui_theme.dart
Normal file
359
apps/packages/design_system/lib/src/ui_theme.dart
Normal file
@@ -0,0 +1,359 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'ui_colors.dart';
|
||||
import 'ui_typography.dart';
|
||||
import 'ui_constants.dart';
|
||||
|
||||
/// The main entry point for the Staff Design System theme.
|
||||
/// Assembles colors, typography, and constants into a comprehensive Material 3 theme.
|
||||
///
|
||||
/// Adheres to the tokens defined in design_tokens_react.md.
|
||||
class UiTheme {
|
||||
UiTheme._();
|
||||
|
||||
/// Returns the light theme for the Staff application.
|
||||
static ThemeData get light {
|
||||
final colorScheme = UiColors.colorScheme;
|
||||
final textTheme = UiTypography.textTheme;
|
||||
|
||||
return ThemeData(
|
||||
useMaterial3: true,
|
||||
colorScheme: colorScheme,
|
||||
scaffoldBackgroundColor: UiColors.background,
|
||||
primaryColor: UiColors.primary,
|
||||
canvasColor: UiColors.background,
|
||||
|
||||
// Typography
|
||||
textTheme: textTheme,
|
||||
|
||||
// Icon Theme
|
||||
iconTheme: const IconThemeData(color: UiColors.iconPrimary, size: 24),
|
||||
|
||||
// Text Selection Theme
|
||||
textSelectionTheme: const TextSelectionThemeData(
|
||||
cursorColor: UiColors.primary,
|
||||
selectionColor: UiColors.primaryInverse,
|
||||
selectionHandleColor: UiColors.primary,
|
||||
),
|
||||
|
||||
// Divider Theme
|
||||
dividerTheme: const DividerThemeData(
|
||||
color: UiColors.separatorPrimary,
|
||||
space: 1,
|
||||
thickness: 1,
|
||||
),
|
||||
|
||||
// Card Theme
|
||||
cardTheme: CardThemeData(
|
||||
color: UiColors.white,
|
||||
elevation: 2,
|
||||
shadowColor: UiColors.popupShadow,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
side: const BorderSide(color: UiColors.borderStill),
|
||||
),
|
||||
margin: EdgeInsets.zero,
|
||||
),
|
||||
|
||||
// Elevated Button Theme (Primary)
|
||||
elevatedButtonTheme: ElevatedButtonThemeData(
|
||||
style:
|
||||
ElevatedButton.styleFrom(
|
||||
elevation: 0,
|
||||
backgroundColor: UiColors.buttonPrimaryStill,
|
||||
foregroundColor: UiColors.primaryForeground,
|
||||
disabledBackgroundColor: UiColors.buttonPrimaryInactive,
|
||||
textStyle: UiTypography.buttonXL,
|
||||
shape: RoundedRectangleBorder(borderRadius: UiConstants.radiusLg),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: UiConstants.space6,
|
||||
vertical: UiConstants.space3,
|
||||
),
|
||||
minimumSize: const Size(double.infinity, 54),
|
||||
maximumSize: const Size(double.infinity, 54),
|
||||
).copyWith(
|
||||
side: WidgetStateProperty.resolveWith<BorderSide?>((states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return const BorderSide(
|
||||
color: UiColors.borderPrimary,
|
||||
width: 0.5,
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
overlayColor: WidgetStateProperty.resolveWith((states) {
|
||||
if (states.contains(WidgetState.hovered))
|
||||
return UiColors.buttonPrimaryHover;
|
||||
return null;
|
||||
}),
|
||||
),
|
||||
),
|
||||
|
||||
// Text Button Theme
|
||||
textButtonTheme: TextButtonThemeData(
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: UiColors.textPrimary,
|
||||
disabledForegroundColor: UiColors.textInactive,
|
||||
textStyle: UiTypography.buttonXL,
|
||||
shape: RoundedRectangleBorder(borderRadius: UiConstants.radiusLg),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: UiConstants.space4,
|
||||
vertical: UiConstants.space2,
|
||||
),
|
||||
minimumSize: const Size(double.infinity, 52),
|
||||
maximumSize: const Size(double.infinity, 52),
|
||||
),
|
||||
),
|
||||
|
||||
// Outlined Button Theme (Secondary)
|
||||
outlinedButtonTheme: OutlinedButtonThemeData(
|
||||
style: OutlinedButton.styleFrom(
|
||||
elevation: 0,
|
||||
backgroundColor: UiColors.buttonSecondaryStill,
|
||||
foregroundColor: UiColors.primary,
|
||||
side: const BorderSide(color: UiColors.borderFocus, width: 0.5),
|
||||
textStyle: UiTypography.buttonXL,
|
||||
shape: RoundedRectangleBorder(borderRadius: UiConstants.radiusLg),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: UiConstants.space4,
|
||||
vertical: UiConstants.space3,
|
||||
),
|
||||
minimumSize: const Size(double.infinity, 52),
|
||||
maximumSize: const Size(double.infinity, 52),
|
||||
),
|
||||
),
|
||||
|
||||
// Icon Button Theme
|
||||
iconButtonTheme: IconButtonThemeData(
|
||||
style: IconButton.styleFrom(
|
||||
foregroundColor: UiColors.iconPrimary,
|
||||
disabledForegroundColor: UiColors.iconInactive,
|
||||
shape: RoundedRectangleBorder(borderRadius: UiConstants.radiusFull),
|
||||
),
|
||||
),
|
||||
|
||||
// Floating Action Button Theme
|
||||
floatingActionButtonTheme: const FloatingActionButtonThemeData(
|
||||
backgroundColor: UiColors.primary,
|
||||
foregroundColor: UiColors.primaryForeground,
|
||||
elevation: 4,
|
||||
shape: CircleBorder(),
|
||||
),
|
||||
|
||||
// Tab Bar Theme
|
||||
tabBarTheme: TabBarThemeData(
|
||||
labelColor: UiColors.primary,
|
||||
unselectedLabelColor: UiColors.textSecondary,
|
||||
labelStyle: UiTypography.buttonM,
|
||||
unselectedLabelStyle: UiTypography.buttonM,
|
||||
indicatorSize: TabBarIndicatorSize.label,
|
||||
indicator: const UnderlineTabIndicator(
|
||||
borderSide: BorderSide(color: UiColors.primary, width: 2),
|
||||
),
|
||||
),
|
||||
|
||||
// Input Theme
|
||||
inputDecorationTheme: InputDecorationTheme(
|
||||
filled: true,
|
||||
fillColor: UiColors.bgInputField,
|
||||
hintStyle: UiTypography.body2r.textPlaceholder,
|
||||
labelStyle: UiTypography.body4r.textPrimary,
|
||||
errorStyle: UiTypography.footnote1r.textError,
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: UiConstants.space3,
|
||||
vertical: UiConstants.space3,
|
||||
),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: UiConstants.radiusMd,
|
||||
borderSide: const BorderSide(color: UiColors.borderStill),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: UiConstants.radiusMd,
|
||||
borderSide: const BorderSide(color: UiColors.borderStill),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: UiConstants.radiusMd,
|
||||
borderSide: const BorderSide(
|
||||
color: UiColors.borderFocus,
|
||||
width: 0.75,
|
||||
),
|
||||
),
|
||||
errorBorder: OutlineInputBorder(
|
||||
borderRadius: UiConstants.radiusMd,
|
||||
borderSide: const BorderSide(color: UiColors.textError),
|
||||
),
|
||||
focusedErrorBorder: OutlineInputBorder(
|
||||
borderRadius: UiConstants.radiusMd,
|
||||
borderSide: const BorderSide(color: UiColors.textError, width: 1),
|
||||
),
|
||||
),
|
||||
|
||||
// List Tile Theme
|
||||
listTileTheme: ListTileThemeData(
|
||||
textColor: UiColors.textPrimary,
|
||||
iconColor: UiColors.iconPrimary,
|
||||
titleTextStyle: UiTypography.body1m,
|
||||
subtitleTextStyle: UiTypography.body2r.textSecondary,
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: UiConstants.space4,
|
||||
),
|
||||
tileColor: UiColors.transparent,
|
||||
),
|
||||
|
||||
// Badge Theme
|
||||
badgeTheme: BadgeThemeData(
|
||||
backgroundColor: UiColors.primary,
|
||||
textColor: UiColors.primaryForeground,
|
||||
textStyle: UiTypography.footnote2m,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||
),
|
||||
|
||||
// App Bar Theme
|
||||
appBarTheme: AppBarTheme(
|
||||
backgroundColor: UiColors.background,
|
||||
elevation: 0,
|
||||
titleTextStyle: UiTypography.headline5m.textPrimary,
|
||||
iconTheme: const IconThemeData(color: UiColors.iconThird, size: 20),
|
||||
surfaceTintColor: UiColors.transparent,
|
||||
),
|
||||
|
||||
// Dialog Theme
|
||||
dialogTheme: DialogThemeData(
|
||||
backgroundColor: UiColors.bgPopup,
|
||||
elevation: 8,
|
||||
shadowColor: UiColors.popupShadow,
|
||||
shape: RoundedRectangleBorder(borderRadius: UiConstants.radiusLg),
|
||||
titleTextStyle: UiTypography.headline2r.textPrimary,
|
||||
contentTextStyle: UiTypography.body2r.textDescription,
|
||||
),
|
||||
|
||||
// Bottom Navigation Bar Theme
|
||||
bottomNavigationBarTheme: BottomNavigationBarThemeData(
|
||||
backgroundColor: UiColors.white,
|
||||
selectedItemColor: UiColors.primary,
|
||||
unselectedItemColor: UiColors.textInactive,
|
||||
selectedLabelStyle: UiTypography.footnote2m,
|
||||
unselectedLabelStyle: UiTypography.footnote2r,
|
||||
type: BottomNavigationBarType.fixed,
|
||||
elevation: 8,
|
||||
),
|
||||
|
||||
// Navigation Bar Theme (Modern M3 Bottom Nav)
|
||||
navigationBarTheme: NavigationBarThemeData(
|
||||
backgroundColor: UiColors.white,
|
||||
indicatorColor: UiColors.primaryInverse.withAlpha(51), // 20% of 255
|
||||
labelTextStyle: WidgetStateProperty.resolveWith((states) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return UiTypography.footnote2m.textPrimary;
|
||||
}
|
||||
return UiTypography.footnote2r.textInactive;
|
||||
}),
|
||||
),
|
||||
|
||||
// Switch Theme
|
||||
switchTheme: SwitchThemeData(
|
||||
trackColor: WidgetStateProperty.resolveWith<Color>((states) {
|
||||
if (states.contains(WidgetState.selected)) {
|
||||
return UiColors.switchActive;
|
||||
}
|
||||
return UiColors.switchInactive;
|
||||
}),
|
||||
thumbColor: const WidgetStatePropertyAll(UiColors.white),
|
||||
),
|
||||
|
||||
// Checkbox Theme
|
||||
checkboxTheme: CheckboxThemeData(
|
||||
fillColor: WidgetStateProperty.resolveWith((states) {
|
||||
if (states.contains(WidgetState.selected)) return UiColors.primary;
|
||||
return null;
|
||||
}),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)),
|
||||
),
|
||||
|
||||
// Radio Theme
|
||||
radioTheme: RadioThemeData(
|
||||
fillColor: WidgetStateProperty.resolveWith((states) {
|
||||
if (states.contains(WidgetState.selected)) return UiColors.primary;
|
||||
return null;
|
||||
}),
|
||||
),
|
||||
|
||||
// Slider Theme
|
||||
sliderTheme: const SliderThemeData(
|
||||
activeTrackColor: UiColors.primary,
|
||||
inactiveTrackColor: UiColors.loaderInactive,
|
||||
thumbColor: UiColors.primary,
|
||||
overlayColor: UiColors.primaryInverse,
|
||||
),
|
||||
|
||||
// Chip Theme
|
||||
chipTheme: ChipThemeData(
|
||||
backgroundColor: UiColors.bgSecondary,
|
||||
labelStyle: UiTypography.footnote1m,
|
||||
secondaryLabelStyle: UiTypography.footnote1m.white,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
shape: RoundedRectangleBorder(borderRadius: UiConstants.radiusMd),
|
||||
side: const BorderSide(color: UiColors.borderStill, width: 0.5),
|
||||
),
|
||||
|
||||
// SnackBar Theme
|
||||
snackBarTheme: SnackBarThemeData(
|
||||
backgroundColor: UiColors.toastBg,
|
||||
contentTextStyle: UiTypography.body2r.white,
|
||||
behavior: SnackBarBehavior.floating,
|
||||
shape: RoundedRectangleBorder(borderRadius: UiConstants.radiusMd),
|
||||
elevation: 4,
|
||||
),
|
||||
|
||||
// Bottom Sheet Theme
|
||||
bottomSheetTheme: const BottomSheetThemeData(
|
||||
backgroundColor: UiColors.bgSecondary,
|
||||
modalBackgroundColor: UiColors.bgSecondary,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(32)),
|
||||
),
|
||||
),
|
||||
|
||||
// Expansion Tile Theme
|
||||
expansionTileTheme: ExpansionTileThemeData(
|
||||
iconColor: UiColors.iconSecondary,
|
||||
collapsedIconColor: UiColors.iconPrimary,
|
||||
backgroundColor: UiColors.bgPopup,
|
||||
collapsedBackgroundColor: UiColors.transparent,
|
||||
textColor: UiColors.textPrimary,
|
||||
collapsedTextColor: UiColors.textPrimary,
|
||||
tilePadding: const EdgeInsets.symmetric(horizontal: UiConstants.space4),
|
||||
shape: RoundedRectangleBorder(borderRadius: UiConstants.radiusMd),
|
||||
collapsedShape: RoundedRectangleBorder(
|
||||
borderRadius: UiConstants.radiusMd,
|
||||
),
|
||||
),
|
||||
|
||||
// Menu Theme
|
||||
menuTheme: MenuThemeData(
|
||||
style: MenuStyle(
|
||||
backgroundColor: WidgetStateProperty.all(UiColors.bgPopup),
|
||||
elevation: WidgetStateProperty.all(4),
|
||||
shape: WidgetStateProperty.all(
|
||||
RoundedRectangleBorder(borderRadius: UiConstants.radiusMd),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Tooltip Theme
|
||||
tooltipTheme: TooltipThemeData(
|
||||
decoration: BoxDecoration(
|
||||
color: UiColors.toastBg.withAlpha(230), // ~90% of 255
|
||||
borderRadius: UiConstants.radiusMd,
|
||||
),
|
||||
textStyle: UiTypography.footnote2r.white,
|
||||
),
|
||||
|
||||
// Progress Indicator Theme
|
||||
progressIndicatorTheme: const ProgressIndicatorThemeData(
|
||||
color: UiColors.primary,
|
||||
linearTrackColor: UiColors.loaderInactive,
|
||||
linearMinHeight: 4,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
564
apps/packages/design_system/lib/src/ui_typography.dart
Normal file
564
apps/packages/design_system/lib/src/ui_typography.dart
Normal file
@@ -0,0 +1,564 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'ui_colors.dart';
|
||||
|
||||
/// Static definitions of typography styles for the Staff Design System.
|
||||
class UiTypography {
|
||||
UiTypography._();
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 0. Base Font Styles
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// The primary font family used throughout the design system.
|
||||
static final TextStyle _primaryBase = GoogleFonts.instrumentSans();
|
||||
|
||||
/// The secondary font family used for display or specialized elements.
|
||||
static final TextStyle _secondaryBase = GoogleFonts.spaceGrotesk();
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 1. Primary Typography (Instrument Sans)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// --- 1.1 Display ---
|
||||
|
||||
/// Display Large - Font: Instrument Sans, Size: 36, Height: 1.1 (#121826)
|
||||
static final TextStyle displayL = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 36,
|
||||
height: 1.1,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Display medium - Font: Instrument Sans, Size: 32, Height: 1.1 (#121826)
|
||||
static final TextStyle displayM = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 32,
|
||||
height: 1.1,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Display small - Font: Instrument Sans, Size: 32, Height: 1.1 (#121826)
|
||||
static final TextStyle displayMb = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 32,
|
||||
height: 1.1,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Display 1 Medium - Font: Instrument Sans, Size: 26, Height: 1.1 (#121826)
|
||||
static final TextStyle display1m = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 26,
|
||||
height: 1.1,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Display 1 Regular - Font: Instrument Sans, Size: 38, Height: 1.3 (#121826)
|
||||
static final TextStyle display1r = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 26,
|
||||
height: 1.3,
|
||||
letterSpacing: -1,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Display 1 Bold - Font: Instrument Sans, Size: 38, Height: 1.3 (#121826)
|
||||
static final TextStyle display1b = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 26,
|
||||
height: 1.3,
|
||||
letterSpacing: -1,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Display 2 Medium - Font: Instrument Sans, Size: 16, Height: 1.1 (#121826)
|
||||
static final TextStyle display2m = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 16,
|
||||
height: 1.1,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Display 2 Regular - Font: Instrument Sans, Size: 28, Height: 1.5 (#121826)
|
||||
static final TextStyle display2r = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 16,
|
||||
height: 1.5,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Display 3 Medium - Font: Instrument Sans, Size: 32, Height: 1.1 (#121826)
|
||||
static final TextStyle display3m = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 14,
|
||||
height: 1.1,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Display 3 Regular - Font: Instrument Sans, Size: 32, Height: 1.3 (#121826)
|
||||
static final TextStyle display3r = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 14,
|
||||
height: 1.3,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Display 3 Bold - Font: Instrument Sans, Size: 32, Height: 1.1 (#121826)
|
||||
static final TextStyle display3b = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14,
|
||||
height: 1.1,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
// --- 1.2 Title ---
|
||||
|
||||
/// Title 1 Medium - Font: Instrument Sans, Size: 18, Height: 1.5 (#121826)
|
||||
static final TextStyle title1m = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 18,
|
||||
height: 1.5,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Title 1 Regular - Font: Instrument Sans, Size: 16, Height: 1.5 (#121826)
|
||||
static final TextStyle title1r = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 18,
|
||||
height: 1.5,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Title 2 Bold - Font: Instrument Sans, Size: 20, Height: 1.1 (#121826)
|
||||
static final TextStyle title2b = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 16,
|
||||
height: 1.1,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Title 2 Medium - Font: Instrument Sans, Size: 16, Height: 1.5 (#121826)
|
||||
static final TextStyle title2m = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 16,
|
||||
height: 1.5,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Title 2 Regular - Font: Instrument Sans, Size: 16, Height: 1.5 (#121826)
|
||||
static final TextStyle title2r = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 16,
|
||||
height: 1.5,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
// --- 1.3 Headline ---
|
||||
|
||||
/// Headline 1 Medium - Font: Instrument Sans, Size: 26, Height: 1.5 (#121826)
|
||||
static final TextStyle headline1m = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 26,
|
||||
height: 1.5,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Headline 1 Regular - Font: Instrument Sans, Size: 26, Height: 1.5 (#121826)
|
||||
static final TextStyle headline1r = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 26,
|
||||
height: 1.5,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Headline 2 Medium - Font: Instrument Sans, Size: 20, Height: 1.5 (#121826)
|
||||
static final TextStyle headline2m = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 22,
|
||||
height: 1.5,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Headline 2 Regular - Font: Instrument Sans, Size: 20, Height: 1.5 (#121826)
|
||||
static final TextStyle headline2r = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 22,
|
||||
height: 1.5,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Headline 3 Medium - Font: Instrument Sans, Size: 22, Height: 1.5 (#121826)
|
||||
static final TextStyle headline3m = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 20,
|
||||
height: 1.5,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Headline 4 Medium - Font: Instrument Sans, Size: 22, Height: 1.5 (#121826)
|
||||
static final TextStyle headline4m = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 18,
|
||||
height: 1.5,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Headline 4 Regular - Font: Instrument Sans, Size: 20, Height: 1.5 (#121826)
|
||||
static final TextStyle headline4r = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 18,
|
||||
height: 1.5,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Headline 5 Regular - Font: Instrument Sans, Size: 18, Height: 1.5 (#121826)
|
||||
static final TextStyle headline5r = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 14,
|
||||
height: 1.5,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Headline 5 Medium - Font: Instrument Sans, Size: 16, Height: 1.5 (#121826)
|
||||
static final TextStyle headline5m = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 16,
|
||||
height: 1.5,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
// --- 1.4 Title Uppercase ---
|
||||
|
||||
/// Title Uppercase 2 Medium - Font: Instrument Sans, Size: 14, Height: 1.5, Spacing: 0.7 (#121826)
|
||||
static final TextStyle titleUppercase2m = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 14,
|
||||
height: 1.5,
|
||||
letterSpacing: 0.7,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Title Uppercase 3 Medium - Font: Instrument Sans, Size: 12, Height: 1.5, Spacing: 1.5 (#121826)
|
||||
static final TextStyle titleUppercase3m = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 12,
|
||||
height: 1.5,
|
||||
letterSpacing: 1.5,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Title Uppercase 4 Medium - Font: Instrument Sans, Size: 11, Height: 1.5, Spacing: 2.2 (#121826)
|
||||
static final TextStyle titleUppercase4m = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 11,
|
||||
height: 1.5,
|
||||
letterSpacing: 2.2,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
// --- 1.5 Body ---
|
||||
|
||||
/// Body 1 Bold - Font: Instrument Sans, Size: 16, Height: 1.5 (#121826)
|
||||
static final TextStyle body1b = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 16,
|
||||
height: 1.5,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Body 1 Medium - Font: Instrument Sans, Size: 16, Height: 1.5 (#121826)
|
||||
static final TextStyle body1m = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 16,
|
||||
height: 1.5,
|
||||
letterSpacing: -0.025,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Body 1 Regular - Font: Instrument Sans, Size: 16, Height: 1.5 (#121826)
|
||||
static final TextStyle body1r = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 16,
|
||||
height: 1.5,
|
||||
letterSpacing: -0.05,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Body 2 Bold - Font: Instrument Sans, Size: 14, Height: 1.5 (#121826)
|
||||
static final TextStyle body2b = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 14,
|
||||
height: 1.5,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Body 2 Medium - Font: Instrument Sans, Size: 14, Height: 1.5 (#121826)
|
||||
static final TextStyle body2m = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 14,
|
||||
height: 1.5,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Body 2 Regular - Font: Instrument Sans, Size: 14, Height: 1.5, Spacing: 0.1 (#121826)
|
||||
static final TextStyle body2r = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 14,
|
||||
height: 1.5,
|
||||
letterSpacing: 0.1,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Body 3 Regular - Font: Instrument Sans, Size: 14, Height: 1.5, Spacing: -0.1 (#121826)
|
||||
static final TextStyle body3r = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 12,
|
||||
height: 1.5,
|
||||
letterSpacing: -0.1,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Body 4 Regular - Font: Instrument Sans, Size: 14, Height: 1.5, Spacing: 0.05 (#121826)
|
||||
static final TextStyle body4r = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 12,
|
||||
height: 1.5,
|
||||
letterSpacing: 0.05,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Body 4 Medium - Font: Instrument Sans, Size: 14, Height: 1.5, Spacing: 0.05 (#121826)
|
||||
static final TextStyle body4m = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 12,
|
||||
height: 1.5,
|
||||
letterSpacing: 0.05,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
// --- 1.6 Footnote ---
|
||||
|
||||
/// Footnote 1 Medium - Font: Instrument Sans, Size: 12, Height: 1.5 (#121826)
|
||||
static final TextStyle footnote1m = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 12,
|
||||
height: 1.5,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Footnote 1 Regular - Font: Instrument Sans, Size: 12, Height: 1.5, Spacing: 0.05 (#121826)
|
||||
static final TextStyle footnote1r = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 12,
|
||||
height: 1.5,
|
||||
letterSpacing: 0.05,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Footnote 1 Bold - Font: Instrument Sans, Size: 12, Height: 1.5, Spacing: 0.05 (#121826)
|
||||
static final TextStyle footnote1b = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 12,
|
||||
height: 1.5,
|
||||
letterSpacing: 0.05,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Footnote 2 Medium - Font: Instrument Sans, Size: 10, Height: 1.5 (#121826)
|
||||
static final TextStyle footnote2m = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 10,
|
||||
height: 1.5,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Footnote 2 Bold - Font: Instrument Sans, Size: 10, Height: 1.5 (#121826)
|
||||
static final TextStyle footnote2b = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 10,
|
||||
height: 1.5,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Footnote 2 Regular - Font: Instrument Sans, Size: 10, Height: 1.5 (#121826)
|
||||
static final TextStyle footnote2r = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 10,
|
||||
height: 1.5,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
// --- 1.7 Button ---
|
||||
|
||||
/// Button S - Font: Instrument Sans, Size: 10, Height: 1.5 (#121826)
|
||||
static final TextStyle buttonS = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 10,
|
||||
height: 1.5,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Button Medium - Font: Instrument Sans, Size: 12, Height: 1.5 (#121826)
|
||||
static final TextStyle buttonM = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 12,
|
||||
height: 1.5,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Button Large - Font: Instrument Sans, Size: 14, Height: 1.5 (#121826)
|
||||
static final TextStyle buttonL = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 14,
|
||||
height: 1.5,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Button XL - Font: Instrument Sans, Size: 16, Height: 1.5 (#121826)
|
||||
static final TextStyle buttonXL = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 16,
|
||||
height: 1.5,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
// --- 1.8 Link ---
|
||||
|
||||
/// Link 1 Regular - Font: Instrument Sans, Size: 16, Height: 1.5, Underlined (#0A39DF)
|
||||
static final TextStyle link1r = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 16,
|
||||
height: 1.5,
|
||||
color: UiColors.textLink,
|
||||
decoration: TextDecoration.underline,
|
||||
decorationColor: UiColors.textLink,
|
||||
);
|
||||
|
||||
/// Link 2 Medium - Font: Instrument Sans, Size: 14, Height: 1.5, Underlined (#0A39DF)
|
||||
static final TextStyle link2m = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 14,
|
||||
height: 1.5,
|
||||
color: UiColors.textLink,
|
||||
decoration: TextDecoration.underline,
|
||||
decorationColor: UiColors.textLink,
|
||||
);
|
||||
|
||||
/// Link 2 Regular - Font: Instrument Sans, Size: 14, Height: 1.5, Underlined (#0A39DF)
|
||||
static final TextStyle link2r = _primaryBase.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 14,
|
||||
height: 1.5,
|
||||
color: UiColors.textLink,
|
||||
decoration: TextDecoration.underline,
|
||||
decorationColor: UiColors.textLink,
|
||||
);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 2. Secondary Typography (Space Grotesk)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// --- 2.1 Display ---
|
||||
|
||||
/// Display 1 Bold (Secondary) - Font: Space Grotesk, Size: 50, Height: 1.1 (#121826)
|
||||
static final TextStyle secondaryDisplay1b = _secondaryBase.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 50,
|
||||
height: 1.1,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Display 1 Regular (Secondary) - Font: Space Grotesk, Size: 50, Height: 1.1 (#121826)
|
||||
static final TextStyle secondaryDisplay1r = _secondaryBase.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 50,
|
||||
height: 1.1,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Display 2 Bold (Secondary) - Font: Space Grotesk, Size: 40, Height: 1.1 (#121826)
|
||||
static final TextStyle secondaryDisplay2b = _secondaryBase.copyWith(
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 40,
|
||||
height: 1.1,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
/// Display 2 Regular (Secondary) - Font: Space Grotesk, Size: 40, Height: 1.1 (#121826)
|
||||
static final TextStyle secondaryDisplay2r = _secondaryBase.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 40,
|
||||
height: 1.1,
|
||||
color: UiColors.textPrimary,
|
||||
);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 3. TextTheme Mapping
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// Primary TextTheme
|
||||
static TextTheme get textTheme => TextTheme(
|
||||
displayLarge: display1r,
|
||||
displayMedium: displayL,
|
||||
displaySmall: display3m,
|
||||
headlineLarge: headline1m,
|
||||
headlineMedium: headline3m,
|
||||
headlineSmall: headline2m,
|
||||
titleLarge: title1m,
|
||||
titleMedium: title2m,
|
||||
titleSmall: body2m,
|
||||
bodyLarge: body1r,
|
||||
bodyMedium: body2r,
|
||||
bodySmall: footnote1r,
|
||||
labelLarge: buttonL,
|
||||
labelMedium: buttonM,
|
||||
labelSmall: footnote2r,
|
||||
);
|
||||
}
|
||||
|
||||
/// Extension to easily color text styles using the Staff Design System color palette.
|
||||
extension TypographyColors on TextStyle {
|
||||
/// Primary text color (#121826)
|
||||
TextStyle get textPrimary => copyWith(color: UiColors.textPrimary);
|
||||
|
||||
/// Secondary text color (#6A7382)
|
||||
TextStyle get textSecondary => copyWith(color: UiColors.textSecondary);
|
||||
|
||||
/// Inactive text color (#9CA3AF)
|
||||
TextStyle get textInactive => copyWith(color: UiColors.textInactive);
|
||||
|
||||
/// Tertiary text color (#9CA3AF)
|
||||
TextStyle get textTertiary => copyWith(color: UiColors.textInactive);
|
||||
|
||||
/// Placeholder text color (#9CA3AF)
|
||||
TextStyle get textPlaceholder => copyWith(color: UiColors.textPlaceholder);
|
||||
|
||||
/// Description text color (#6A7382)
|
||||
TextStyle get textDescription => copyWith(color: UiColors.textDescription);
|
||||
|
||||
/// Success text color (#10B981)
|
||||
TextStyle get textSuccess => copyWith(color: UiColors.textSuccess);
|
||||
|
||||
/// Error text color (#F04444)
|
||||
TextStyle get textError => copyWith(color: UiColors.textError);
|
||||
|
||||
/// Warning text color (#D97706)
|
||||
TextStyle get textWarning => copyWith(color: UiColors.textWarning);
|
||||
|
||||
/// Link text color (#0A39DF)
|
||||
TextStyle get textLink => copyWith(color: UiColors.textLink);
|
||||
|
||||
/// White text color (#FFFFFF)
|
||||
TextStyle get white => copyWith(color: UiColors.white);
|
||||
|
||||
/// Black text color (#000000)
|
||||
TextStyle get black => copyWith(color: UiColors.black);
|
||||
|
||||
/// Underline decoration
|
||||
TextStyle get underline => copyWith(decoration: TextDecoration.underline);
|
||||
|
||||
/// Active content color
|
||||
TextStyle get activeContentColor => copyWith(color: UiColors.textPrimary);
|
||||
}
|
||||
76
apps/packages/design_system/lib/src/widgets/ui_app_bar.dart
Normal file
76
apps/packages/design_system/lib/src/widgets/ui_app_bar.dart
Normal file
@@ -0,0 +1,76 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../ui_icons.dart';
|
||||
|
||||
/// A custom AppBar for the Krow UI design system.
|
||||
///
|
||||
/// This widget provides a consistent look and feel for top app bars across the application.
|
||||
class UiAppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||
/// The title text to display in the app bar.
|
||||
final String? title;
|
||||
|
||||
/// A widget to display instead of the title text.
|
||||
final Widget? titleWidget;
|
||||
|
||||
/// The widget to display before the title.
|
||||
/// Usually an [IconButton] for navigation.
|
||||
final Widget? leading;
|
||||
|
||||
/// A list of Widgets to display in a row after the [title] widget.
|
||||
final List<Widget>? actions;
|
||||
|
||||
/// The height of the app bar. Defaults to [kToolbarHeight].
|
||||
final double height;
|
||||
|
||||
/// Whether the title should be centered.
|
||||
final bool centerTitle;
|
||||
|
||||
/// Signature for the callback that is called when the leading button is pressed.
|
||||
/// If [leading] is null, this callback will be used for a default back button.
|
||||
final VoidCallback? onLeadingPressed;
|
||||
|
||||
/// Whether to show a default back button if [leading] is null.
|
||||
final bool showBackButton;
|
||||
|
||||
/// This widget appears across the bottom of the app bar.
|
||||
/// Typically a [TabBar]. Only widgets that implement [PreferredSizeWidget] can be used at the bottom of an app bar.
|
||||
final PreferredSizeWidget? bottom;
|
||||
|
||||
const UiAppBar({
|
||||
super.key,
|
||||
this.title,
|
||||
this.titleWidget,
|
||||
this.leading,
|
||||
this.actions,
|
||||
this.height = kToolbarHeight,
|
||||
this.centerTitle = true,
|
||||
this.onLeadingPressed,
|
||||
this.showBackButton = true,
|
||||
this.bottom,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AppBar(
|
||||
title: titleWidget ??
|
||||
(title != null
|
||||
? Text(
|
||||
title!,
|
||||
)
|
||||
: null),
|
||||
leading: leading ??
|
||||
(showBackButton
|
||||
? IconButton(
|
||||
icon: const Icon(UiIcons.chevronLeft, size: 20),
|
||||
onPressed: onLeadingPressed ?? () => Navigator.of(context).pop(),
|
||||
)
|
||||
: null),
|
||||
actions: actions,
|
||||
centerTitle: centerTitle,
|
||||
bottom: bottom,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Size get preferredSize => Size.fromHeight(height + (bottom?.preferredSize.height ?? 0.0));
|
||||
}
|
||||
191
apps/packages/design_system/lib/src/widgets/ui_button.dart
Normal file
191
apps/packages/design_system/lib/src/widgets/ui_button.dart
Normal file
@@ -0,0 +1,191 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../ui_constants.dart';
|
||||
|
||||
/// A custom button widget with different variants and icon support.
|
||||
class UiButton extends StatelessWidget {
|
||||
/// The text to display on the button.
|
||||
final String? text;
|
||||
|
||||
/// Optional custom child widget. If provided, overrides text and icons.
|
||||
final Widget? child;
|
||||
|
||||
/// Callback when the button is tapped.
|
||||
final VoidCallback? onPressed;
|
||||
|
||||
/// Optional leading icon.
|
||||
final IconData? leadingIcon;
|
||||
|
||||
/// Optional trailing icon.
|
||||
final IconData? trailingIcon;
|
||||
|
||||
/// Optional Style
|
||||
final ButtonStyle? style;
|
||||
|
||||
/// The size of the icons. Defaults to 20.
|
||||
final double iconSize;
|
||||
|
||||
/// The size of the button.
|
||||
final UiButtonSize size;
|
||||
|
||||
/// The button widget to use (ElevatedButton, OutlinedButton, or TextButton).
|
||||
final Widget Function(
|
||||
BuildContext context,
|
||||
VoidCallback? onPressed,
|
||||
ButtonStyle? style,
|
||||
Widget child,
|
||||
)
|
||||
buttonBuilder;
|
||||
|
||||
/// Creates a [UiButton] with a custom button builder.
|
||||
const UiButton({
|
||||
super.key,
|
||||
this.text,
|
||||
this.child,
|
||||
required this.buttonBuilder,
|
||||
this.onPressed,
|
||||
this.leadingIcon,
|
||||
this.trailingIcon,
|
||||
this.style,
|
||||
this.iconSize = 20,
|
||||
this.size = UiButtonSize.medium,
|
||||
}) : assert(
|
||||
text != null || child != null,
|
||||
'Either text or child must be provided',
|
||||
);
|
||||
|
||||
/// Creates a primary button using [ElevatedButton].
|
||||
UiButton.primary({
|
||||
super.key,
|
||||
this.text,
|
||||
this.child,
|
||||
this.onPressed,
|
||||
this.leadingIcon,
|
||||
this.trailingIcon,
|
||||
this.style,
|
||||
this.iconSize = 20,
|
||||
this.size = UiButtonSize.medium,
|
||||
}) : buttonBuilder = _elevatedButtonBuilder,
|
||||
assert(
|
||||
text != null || child != null,
|
||||
'Either text or child must be provided',
|
||||
);
|
||||
|
||||
/// Creates a secondary button using [OutlinedButton].
|
||||
UiButton.secondary({
|
||||
super.key,
|
||||
this.text,
|
||||
this.child,
|
||||
this.onPressed,
|
||||
this.leadingIcon,
|
||||
this.trailingIcon,
|
||||
this.style,
|
||||
this.iconSize = 20,
|
||||
this.size = UiButtonSize.medium,
|
||||
}) : buttonBuilder = _outlinedButtonBuilder,
|
||||
assert(
|
||||
text != null || child != null,
|
||||
'Either text or child must be provided',
|
||||
);
|
||||
|
||||
/// Creates a text button using [TextButton].
|
||||
UiButton.text({
|
||||
super.key,
|
||||
this.text,
|
||||
this.child,
|
||||
this.onPressed,
|
||||
this.leadingIcon,
|
||||
this.trailingIcon,
|
||||
this.style,
|
||||
this.iconSize = 20,
|
||||
this.size = UiButtonSize.medium,
|
||||
}) : buttonBuilder = _textButtonBuilder,
|
||||
assert(
|
||||
text != null || child != null,
|
||||
'Either text or child must be provided',
|
||||
);
|
||||
|
||||
@override
|
||||
/// Builds the button UI.
|
||||
Widget build(BuildContext context) {
|
||||
return buttonBuilder(context, onPressed, style, _buildButtonContent());
|
||||
}
|
||||
|
||||
/// Builds the button content with optional leading and trailing icons.
|
||||
Widget _buildButtonContent() {
|
||||
if (child != null) {
|
||||
return child!;
|
||||
}
|
||||
|
||||
// Single icon or text case
|
||||
if (leadingIcon == null && trailingIcon == null) {
|
||||
return Text(text!);
|
||||
}
|
||||
|
||||
if (leadingIcon != null && text == null && trailingIcon == null) {
|
||||
return Icon(leadingIcon, size: iconSize);
|
||||
}
|
||||
|
||||
// Multiple elements case
|
||||
final List<Widget> children = [];
|
||||
|
||||
if (leadingIcon != null) {
|
||||
children.add(Icon(leadingIcon, size: iconSize));
|
||||
children.add(const SizedBox(width: UiConstants.space2));
|
||||
}
|
||||
|
||||
children.add(Text(text!));
|
||||
|
||||
if (trailingIcon != null) {
|
||||
children.add(const SizedBox(width: UiConstants.space2));
|
||||
children.add(Icon(trailingIcon, size: iconSize));
|
||||
}
|
||||
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: children,
|
||||
);
|
||||
}
|
||||
|
||||
/// Builder for ElevatedButton.
|
||||
static Widget _elevatedButtonBuilder(
|
||||
BuildContext context,
|
||||
VoidCallback? onPressed,
|
||||
ButtonStyle? style,
|
||||
Widget child,
|
||||
) {
|
||||
return ElevatedButton(onPressed: onPressed, style: style, child: child);
|
||||
}
|
||||
|
||||
/// Builder for OutlinedButton.
|
||||
static Widget _outlinedButtonBuilder(
|
||||
BuildContext context,
|
||||
VoidCallback? onPressed,
|
||||
ButtonStyle? style,
|
||||
Widget child,
|
||||
) {
|
||||
return OutlinedButton(onPressed: onPressed, style: style, child: child);
|
||||
}
|
||||
|
||||
/// Builder for TextButton.
|
||||
static Widget _textButtonBuilder(
|
||||
BuildContext context,
|
||||
VoidCallback? onPressed,
|
||||
ButtonStyle? style,
|
||||
Widget child,
|
||||
) {
|
||||
return TextButton(onPressed: onPressed, style: style, child: child);
|
||||
}
|
||||
}
|
||||
|
||||
/// Defines the size of a [UiButton].
|
||||
enum UiButtonSize {
|
||||
/// Small button (compact)
|
||||
small,
|
||||
|
||||
/// Medium button (standard)
|
||||
medium,
|
||||
|
||||
/// Large button (prominent)
|
||||
large,
|
||||
}
|
||||
190
apps/packages/design_system/lib/src/widgets/ui_chip.dart
Normal file
190
apps/packages/design_system/lib/src/widgets/ui_chip.dart
Normal file
@@ -0,0 +1,190 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../ui_colors.dart';
|
||||
import '../ui_constants.dart';
|
||||
import '../ui_typography.dart';
|
||||
|
||||
/// Sizes for the [UiChip] widget.
|
||||
enum UiChipSize {
|
||||
/// Small size (e.g. for tags in tight spaces).
|
||||
small,
|
||||
|
||||
/// Medium size (default).
|
||||
medium,
|
||||
|
||||
/// Large size (e.g. for standalone filters).
|
||||
large,
|
||||
}
|
||||
|
||||
/// Themes for the [UiChip] widget.
|
||||
enum UiChipVariant {
|
||||
/// Primary style with solid background.
|
||||
primary,
|
||||
|
||||
/// Secondary style with light background.
|
||||
secondary,
|
||||
|
||||
/// Accent style with highlight background.
|
||||
accent,
|
||||
}
|
||||
|
||||
/// A custom chip widget with supports for different sizes, themes, and icons.
|
||||
class UiChip extends StatelessWidget {
|
||||
/// The text label to display.
|
||||
final String label;
|
||||
|
||||
/// The size of the chip. Defaults to [UiChipSize.medium].
|
||||
final UiChipSize size;
|
||||
|
||||
/// The theme variant of the chip. Defaults to [UiChipVariant.secondary].
|
||||
final UiChipVariant variant;
|
||||
|
||||
/// Optional leading icon.
|
||||
final IconData? leadingIcon;
|
||||
|
||||
/// Optional trailing icon.
|
||||
final IconData? trailingIcon;
|
||||
|
||||
/// Callback when the chip is tapped.
|
||||
final VoidCallback? onTap;
|
||||
|
||||
/// Callback when the trailing icon is tapped (e.g. for removal).
|
||||
final VoidCallback? onTrailingIconTap;
|
||||
|
||||
/// Whether the chip is currently selected/active.
|
||||
final bool isSelected;
|
||||
|
||||
/// Creates a [UiChip].
|
||||
const UiChip({
|
||||
super.key,
|
||||
required this.label,
|
||||
this.size = UiChipSize.medium,
|
||||
this.variant = UiChipVariant.secondary,
|
||||
this.leadingIcon,
|
||||
this.trailingIcon,
|
||||
this.onTap,
|
||||
this.onTrailingIconTap,
|
||||
this.isSelected = false,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final backgroundColor = _getBackgroundColor();
|
||||
final contentColor = _getContentColor();
|
||||
final textStyle = _getTextStyle().copyWith(color: contentColor);
|
||||
final padding = _getPadding();
|
||||
final iconSize = _getIconSize();
|
||||
|
||||
final content = Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (leadingIcon != null) ...[
|
||||
Icon(leadingIcon, size: iconSize, color: contentColor),
|
||||
SizedBox(width: _getGap()),
|
||||
],
|
||||
Text(label, style: textStyle),
|
||||
if (trailingIcon != null) ...[
|
||||
SizedBox(width: _getGap()),
|
||||
GestureDetector(
|
||||
onTap: onTrailingIconTap,
|
||||
child: Icon(trailingIcon, size: iconSize, color: contentColor),
|
||||
),
|
||||
],
|
||||
],
|
||||
);
|
||||
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
padding: padding,
|
||||
decoration: BoxDecoration(
|
||||
color: backgroundColor,
|
||||
borderRadius: UiConstants.radiusFull,
|
||||
border: _getBorder(),
|
||||
),
|
||||
child: content,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Color _getBackgroundColor() {
|
||||
if (!isSelected && variant == UiChipVariant.primary) {
|
||||
return UiColors.white;
|
||||
}
|
||||
|
||||
switch (variant) {
|
||||
case UiChipVariant.primary:
|
||||
return UiColors.primary;
|
||||
case UiChipVariant.secondary:
|
||||
return UiColors.tagInProgress;
|
||||
case UiChipVariant.accent:
|
||||
return UiColors.accent;
|
||||
}
|
||||
}
|
||||
|
||||
Color _getContentColor() {
|
||||
if (!isSelected && variant == UiChipVariant.primary) {
|
||||
return UiColors.textSecondary;
|
||||
}
|
||||
|
||||
switch (variant) {
|
||||
case UiChipVariant.primary:
|
||||
return UiColors.white;
|
||||
case UiChipVariant.secondary:
|
||||
return UiColors.primary;
|
||||
case UiChipVariant.accent:
|
||||
return UiColors.accentForeground;
|
||||
}
|
||||
}
|
||||
|
||||
TextStyle _getTextStyle() {
|
||||
switch (size) {
|
||||
case UiChipSize.small:
|
||||
return UiTypography.body3r;
|
||||
case UiChipSize.medium:
|
||||
return UiTypography.body2m;
|
||||
case UiChipSize.large:
|
||||
return UiTypography.body1m;
|
||||
}
|
||||
}
|
||||
|
||||
EdgeInsets _getPadding() {
|
||||
switch (size) {
|
||||
case UiChipSize.small:
|
||||
return const EdgeInsets.symmetric(horizontal: 10, vertical: 6);
|
||||
case UiChipSize.medium:
|
||||
return const EdgeInsets.symmetric(horizontal: 12, vertical: 8);
|
||||
case UiChipSize.large:
|
||||
return const EdgeInsets.symmetric(horizontal: 16, vertical: 10);
|
||||
}
|
||||
}
|
||||
|
||||
double _getIconSize() {
|
||||
switch (size) {
|
||||
case UiChipSize.small:
|
||||
return 12;
|
||||
case UiChipSize.medium:
|
||||
return 16;
|
||||
case UiChipSize.large:
|
||||
return 20;
|
||||
}
|
||||
}
|
||||
|
||||
double _getGap() {
|
||||
switch (size) {
|
||||
case UiChipSize.small:
|
||||
return UiConstants.space1;
|
||||
case UiChipSize.medium:
|
||||
return UiConstants.space1 + 2;
|
||||
case UiChipSize.large:
|
||||
return UiConstants.space2;
|
||||
}
|
||||
}
|
||||
|
||||
BoxBorder? _getBorder() {
|
||||
if (!isSelected && variant == UiChipVariant.primary) {
|
||||
return Border.all(color: UiColors.border);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
import 'dart:ui';
|
||||
import 'package:flutter/material.dart';
|
||||
import '../ui_colors.dart';
|
||||
import '../ui_constants.dart';
|
||||
|
||||
/// A custom icon button with blur effect and different variants.
|
||||
class UiIconButton extends StatelessWidget {
|
||||
/// The icon to display.
|
||||
final IconData icon;
|
||||
|
||||
/// The size of the icon button.
|
||||
final double size;
|
||||
|
||||
/// The size of the icon.
|
||||
final double iconSize;
|
||||
|
||||
/// The background color of the button.
|
||||
final Color backgroundColor;
|
||||
|
||||
/// The color of the icon.
|
||||
final Color iconColor;
|
||||
|
||||
/// Whether to apply blur effect.
|
||||
final bool useBlur;
|
||||
|
||||
/// Callback when the button is tapped.
|
||||
final VoidCallback? onTap;
|
||||
|
||||
/// Creates a [UiIconButton] with custom properties.
|
||||
const UiIconButton({
|
||||
super.key,
|
||||
required this.icon,
|
||||
this.size = 40,
|
||||
this.iconSize = 20,
|
||||
required this.backgroundColor,
|
||||
required this.iconColor,
|
||||
this.useBlur = false,
|
||||
this.onTap,
|
||||
});
|
||||
|
||||
/// Creates a primary variant icon button with solid background.
|
||||
const UiIconButton.primary({
|
||||
super.key,
|
||||
required this.icon,
|
||||
this.size = 40,
|
||||
this.iconSize = 20,
|
||||
this.onTap,
|
||||
}) : backgroundColor = UiColors.primary,
|
||||
iconColor = UiColors.white,
|
||||
useBlur = false;
|
||||
|
||||
/// Creates a secondary variant icon button with blur effect.
|
||||
UiIconButton.secondary({
|
||||
super.key,
|
||||
required this.icon,
|
||||
this.size = 40,
|
||||
this.iconSize = 20,
|
||||
this.onTap,
|
||||
}) : backgroundColor = UiColors.primary.withAlpha(96),
|
||||
iconColor = UiColors.primary,
|
||||
useBlur = true;
|
||||
|
||||
@override
|
||||
/// Builds the icon button UI.
|
||||
Widget build(BuildContext context) {
|
||||
final Widget button = Container(
|
||||
width: size,
|
||||
height: size,
|
||||
decoration: BoxDecoration(color: backgroundColor, shape: BoxShape.circle),
|
||||
child: Icon(icon, color: iconColor, size: iconSize),
|
||||
);
|
||||
|
||||
final Widget content = useBlur
|
||||
? ClipRRect(
|
||||
borderRadius: UiConstants.radiusFull,
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
|
||||
child: button,
|
||||
),
|
||||
)
|
||||
: button;
|
||||
|
||||
if (onTap != null) {
|
||||
return GestureDetector(onTap: onTap, child: content);
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../ui_colors.dart';
|
||||
import '../ui_constants.dart';
|
||||
import '../ui_icons.dart';
|
||||
|
||||
/// A widget that displays a horizontal step indicator with icons.
|
||||
///
|
||||
/// This widget shows a series of circular step indicators connected by lines,
|
||||
/// with different visual states for completed, active, and inactive steps.
|
||||
class UiStepIndicator extends StatelessWidget {
|
||||
/// The list of icons to display for each step.
|
||||
final List<IconData> stepIcons;
|
||||
|
||||
/// The index of the currently active step (0-based).
|
||||
final int currentStep;
|
||||
|
||||
/// Creates a [UiStepIndicator].
|
||||
const UiStepIndicator({
|
||||
super.key,
|
||||
required this.stepIcons,
|
||||
required this.currentStep,
|
||||
});
|
||||
|
||||
@override
|
||||
/// Builds the step indicator UI.
|
||||
Widget build(BuildContext context) {
|
||||
// active step color
|
||||
const Color activeColor = UiColors.primary;
|
||||
// completed step color
|
||||
const Color completedColor = UiColors.textSuccess;
|
||||
// inactive step color
|
||||
const Color inactiveColor = UiColors.iconSecondary;
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: UiConstants.space2),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: List.generate(stepIcons.length, (index) {
|
||||
final bool isActive = index == currentStep;
|
||||
final bool isCompleted = index < currentStep;
|
||||
|
||||
Color bgColor;
|
||||
Color iconColor;
|
||||
if (isCompleted) {
|
||||
bgColor = completedColor.withAlpha(24);
|
||||
iconColor = completedColor;
|
||||
} else if (isActive) {
|
||||
bgColor = activeColor.withAlpha(24);
|
||||
iconColor = activeColor;
|
||||
} else {
|
||||
bgColor = inactiveColor.withAlpha(24);
|
||||
iconColor = inactiveColor.withAlpha(128);
|
||||
}
|
||||
|
||||
return Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 40,
|
||||
height: 40,
|
||||
decoration: BoxDecoration(
|
||||
color: bgColor,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Icon(
|
||||
isCompleted ? UiIcons.check : stepIcons[index],
|
||||
size: 20,
|
||||
color: iconColor,
|
||||
),
|
||||
),
|
||||
if (index < stepIcons.length - 1)
|
||||
Container(
|
||||
width: 30,
|
||||
height: 2,
|
||||
margin: const EdgeInsets.symmetric(
|
||||
horizontal: UiConstants.space1,
|
||||
),
|
||||
color: isCompleted
|
||||
? completedColor.withAlpha(96)
|
||||
: inactiveColor.withAlpha(96),
|
||||
),
|
||||
],
|
||||
);
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
115
apps/packages/design_system/lib/src/widgets/ui_text_field.dart
Normal file
115
apps/packages/design_system/lib/src/widgets/ui_text_field.dart
Normal file
@@ -0,0 +1,115 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import '../ui_typography.dart';
|
||||
import '../ui_constants.dart';
|
||||
import '../ui_colors.dart';
|
||||
|
||||
/// A custom TextField for the Krow UI design system.
|
||||
///
|
||||
/// This widget combines a label and a [TextField] with consistent styling.
|
||||
class UiTextField extends StatelessWidget {
|
||||
/// The label text to display above the text field.
|
||||
final String? label;
|
||||
|
||||
/// The hint text to display inside the text field when empty.
|
||||
final String? hintText;
|
||||
|
||||
/// Signature for the callback that is called when the text in the field changes.
|
||||
final ValueChanged<String>? onChanged;
|
||||
|
||||
/// The controller for the text field.
|
||||
final TextEditingController? controller;
|
||||
|
||||
/// The type of keyboard to use for editing the text.
|
||||
final TextInputType? keyboardType;
|
||||
|
||||
/// The maximum number of lines for the text field. Defaults to 1.
|
||||
final int? maxLines;
|
||||
|
||||
/// Whether to hide the text being edited (e.g., for passwords). Defaults to false.
|
||||
final bool obscureText;
|
||||
|
||||
/// The type of action button to use for the keyboard.
|
||||
final TextInputAction? textInputAction;
|
||||
|
||||
/// Signature for the callback that is called when the user submits the text field.
|
||||
final ValueChanged<String>? onSubmitted;
|
||||
|
||||
/// Whether the text field should be focused automatically. Defaults to false.
|
||||
final bool autofocus;
|
||||
|
||||
/// Optional input formatters to validate or format the text as it is typed.
|
||||
final List<TextInputFormatter>? inputFormatters;
|
||||
|
||||
/// Optional prefix icon to display at the start of the text field.
|
||||
final IconData? prefixIcon;
|
||||
|
||||
/// Optional suffix icon to display at the end of the text field.
|
||||
final IconData? suffixIcon;
|
||||
|
||||
/// Optional custom suffix widget to display at the end (e.g., password toggle).
|
||||
final Widget? suffix;
|
||||
|
||||
/// Whether the text field should be read-only.
|
||||
final bool readOnly;
|
||||
|
||||
/// Callback when the text field is tapped.
|
||||
final VoidCallback? onTap;
|
||||
|
||||
const UiTextField({
|
||||
super.key,
|
||||
this.label,
|
||||
this.hintText,
|
||||
this.onChanged,
|
||||
this.controller,
|
||||
this.keyboardType,
|
||||
this.maxLines = 1,
|
||||
this.obscureText = false,
|
||||
this.textInputAction,
|
||||
this.onSubmitted,
|
||||
this.autofocus = false,
|
||||
this.inputFormatters,
|
||||
this.prefixIcon,
|
||||
this.suffixIcon,
|
||||
this.suffix,
|
||||
this.readOnly = false,
|
||||
this.onTap,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (label != null) ...[
|
||||
Text(label!, style: UiTypography.body4m.textSecondary),
|
||||
const SizedBox(height: UiConstants.space1),
|
||||
],
|
||||
TextField(
|
||||
controller: controller,
|
||||
onChanged: onChanged,
|
||||
keyboardType: keyboardType,
|
||||
maxLines: maxLines,
|
||||
obscureText: obscureText,
|
||||
textInputAction: textInputAction,
|
||||
onSubmitted: onSubmitted,
|
||||
autofocus: autofocus,
|
||||
inputFormatters: inputFormatters,
|
||||
readOnly: readOnly,
|
||||
onTap: onTap,
|
||||
style: UiTypography.body1r.textPrimary,
|
||||
decoration: InputDecoration(
|
||||
hintText: hintText,
|
||||
prefixIcon: prefixIcon != null
|
||||
? Icon(prefixIcon, size: 20, color: UiColors.iconSecondary)
|
||||
: null,
|
||||
suffixIcon: suffixIcon != null
|
||||
? Icon(suffixIcon, size: 20, color: UiColors.iconSecondary)
|
||||
: suffix,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
31
apps/packages/design_system/pubspec.yaml
Normal file
31
apps/packages/design_system/pubspec.yaml
Normal file
@@ -0,0 +1,31 @@
|
||||
name: design_system
|
||||
description: "A new Flutter package project."
|
||||
version: 0.0.1
|
||||
homepage:
|
||||
resolution: workspace
|
||||
|
||||
environment:
|
||||
sdk: ^3.10.7
|
||||
flutter: ">=1.17.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
google_fonts: ^7.0.2
|
||||
lucide_icons: ^0.257.0
|
||||
font_awesome_flutter: ^10.7.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
flutter_lints: ^6.0.0
|
||||
|
||||
# For information on the generic Dart part of this file, see the
|
||||
# following page: https://dart.dev/tools/pub/pubspec
|
||||
|
||||
# The following section is specific to Flutter packages.
|
||||
flutter:
|
||||
|
||||
# To add assets to your package, add an assets section, like this:
|
||||
assets:
|
||||
- assets/
|
||||
12
apps/packages/design_system/test/design_system_test.dart
Normal file
12
apps/packages/design_system/test/design_system_test.dart
Normal file
@@ -0,0 +1,12 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'package:design_system/design_system.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);
|
||||
});
|
||||
}
|
||||
57
apps/packages/domain/lib/krow_domain.dart
Normal file
57
apps/packages/domain/lib/krow_domain.dart
Normal file
@@ -0,0 +1,57 @@
|
||||
/// The Shared Domain Layer.
|
||||
///
|
||||
/// This package contains the core business entities and rules.
|
||||
/// It is pure Dart and has no dependencies on Flutter or Firebase.
|
||||
///
|
||||
/// Note: Repository Interfaces are now located in their respective Feature packages.
|
||||
|
||||
// Users & Membership
|
||||
export 'src/entities/users/user.dart';
|
||||
export 'src/entities/users/staff.dart';
|
||||
export 'src/entities/users/membership.dart';
|
||||
export 'src/entities/users/biz_member.dart';
|
||||
export 'src/entities/users/hub_member.dart';
|
||||
|
||||
// Business & Organization
|
||||
export 'src/entities/business/business.dart';
|
||||
export 'src/entities/business/business_setting.dart';
|
||||
export 'src/entities/business/hub.dart';
|
||||
export 'src/entities/business/hub_department.dart';
|
||||
export 'src/entities/business/biz_contract.dart';
|
||||
|
||||
// Events & Shifts
|
||||
export 'src/entities/events/event.dart';
|
||||
export 'src/entities/events/event_shift.dart';
|
||||
export 'src/entities/events/event_shift_position.dart';
|
||||
export 'src/entities/events/assignment.dart';
|
||||
export 'src/entities/events/work_session.dart';
|
||||
|
||||
// Skills & Certs
|
||||
export 'src/entities/skills/skill.dart';
|
||||
export 'src/entities/skills/skill_category.dart';
|
||||
export 'src/entities/skills/staff_skill.dart';
|
||||
export 'src/entities/skills/certificate.dart';
|
||||
export 'src/entities/skills/skill_kit.dart';
|
||||
|
||||
// Financial & Payroll
|
||||
export 'src/entities/financial/invoice.dart';
|
||||
export 'src/entities/financial/invoice_item.dart';
|
||||
export 'src/entities/financial/invoice_decline.dart';
|
||||
export 'src/entities/financial/staff_payment.dart';
|
||||
|
||||
// Ratings & Penalties
|
||||
export 'src/entities/ratings/staff_rating.dart';
|
||||
export 'src/entities/ratings/penalty_log.dart';
|
||||
export 'src/entities/ratings/business_staff_preference.dart';
|
||||
|
||||
// Staff Profile
|
||||
export 'src/entities/profile/emergency_contact.dart';
|
||||
export 'src/entities/profile/bank_account.dart';
|
||||
export 'src/entities/profile/accessibility.dart';
|
||||
export 'src/entities/profile/schedule.dart';
|
||||
|
||||
// Support & Config
|
||||
export 'src/entities/support/addon.dart';
|
||||
export 'src/entities/support/tag.dart';
|
||||
export 'src/entities/support/media.dart';
|
||||
export 'src/entities/support/working_area.dart';
|
||||
@@ -0,0 +1,36 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// Represents a legal or service contract.
|
||||
///
|
||||
/// Can be between a business and the platform, or a business and staff.
|
||||
class BizContract extends Equatable {
|
||||
/// Unique identifier.
|
||||
final String id;
|
||||
|
||||
/// The [Business] party to the contract.
|
||||
final String businessId;
|
||||
|
||||
/// Descriptive name of the contract.
|
||||
final String name;
|
||||
|
||||
/// Valid from date.
|
||||
final DateTime startDate;
|
||||
|
||||
/// Valid until date (null if indefinite).
|
||||
final DateTime? endDate;
|
||||
|
||||
/// URL to the document content (PDF/HTML).
|
||||
final String contentUrl;
|
||||
|
||||
const BizContract({
|
||||
required this.id,
|
||||
required this.businessId,
|
||||
required this.name,
|
||||
required this.startDate,
|
||||
this.endDate,
|
||||
required this.contentUrl,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [id, businessId, name, startDate, endDate, contentUrl];
|
||||
}
|
||||
47
apps/packages/domain/lib/src/entities/business/business.dart
Normal file
47
apps/packages/domain/lib/src/entities/business/business.dart
Normal file
@@ -0,0 +1,47 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// The operating status of a [Business].
|
||||
enum BusinessStatus {
|
||||
/// Business created but not yet approved.
|
||||
pending,
|
||||
|
||||
/// Fully active and operational.
|
||||
active,
|
||||
|
||||
/// Temporarily suspended (e.g. for non-payment).
|
||||
suspended,
|
||||
|
||||
/// Permanently inactive.
|
||||
inactive,
|
||||
}
|
||||
|
||||
/// Represents a Client Company / Business.
|
||||
///
|
||||
/// This is the top-level organizational entity in the system.
|
||||
class Business extends Equatable {
|
||||
/// Unique identifier for the business.
|
||||
final String id;
|
||||
|
||||
/// Display name of the business.
|
||||
final String name;
|
||||
|
||||
/// Legal registration or tax number.
|
||||
final String registrationNumber;
|
||||
|
||||
/// Current operating status.
|
||||
final BusinessStatus status;
|
||||
|
||||
/// URL to the business logo.
|
||||
final String? avatar;
|
||||
|
||||
const Business({
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.registrationNumber,
|
||||
required this.status,
|
||||
this.avatar,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [id, name, registrationNumber, status, avatar];
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// Represents payroll and operational configuration for a [Business].
|
||||
class BusinessSetting extends Equatable {
|
||||
/// Unique identifier for the settings record.
|
||||
final String id;
|
||||
|
||||
/// The [Business] these settings apply to.
|
||||
final String businessId;
|
||||
|
||||
/// Prefix for generated invoices (e.g., "INV-").
|
||||
final String prefix;
|
||||
|
||||
/// Whether overtime calculations are applied.
|
||||
final bool overtimeEnabled;
|
||||
|
||||
/// Requirement method for clocking in (e.g. "qr_code", "geo_fence").
|
||||
final String? clockInRequirement;
|
||||
|
||||
/// Requirement method for clocking out.
|
||||
final String? clockOutRequirement;
|
||||
|
||||
const BusinessSetting({
|
||||
required this.id,
|
||||
required this.businessId,
|
||||
required this.prefix,
|
||||
required this.overtimeEnabled,
|
||||
this.clockInRequirement,
|
||||
this.clockOutRequirement,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
id,
|
||||
businessId,
|
||||
prefix,
|
||||
overtimeEnabled,
|
||||
clockInRequirement,
|
||||
clockOutRequirement,
|
||||
];
|
||||
}
|
||||
42
apps/packages/domain/lib/src/entities/business/hub.dart
Normal file
42
apps/packages/domain/lib/src/entities/business/hub.dart
Normal file
@@ -0,0 +1,42 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// The status of a [Hub].
|
||||
enum HubStatus {
|
||||
/// Fully operational.
|
||||
active,
|
||||
|
||||
/// Closed or inactive.
|
||||
inactive,
|
||||
|
||||
/// Not yet ready for operations.
|
||||
underConstruction,
|
||||
}
|
||||
|
||||
/// Represents a branch location or operational unit within a [Business].
|
||||
class Hub extends Equatable {
|
||||
/// Unique identifier.
|
||||
final String id;
|
||||
|
||||
/// The parent [Business].
|
||||
final String businessId;
|
||||
|
||||
/// Display name of the hub (e.g. "Downtown Branch").
|
||||
final String name;
|
||||
|
||||
/// Physical address of this hub.
|
||||
final String address;
|
||||
|
||||
/// Operational status.
|
||||
final HubStatus status;
|
||||
|
||||
const Hub({
|
||||
required this.id,
|
||||
required this.businessId,
|
||||
required this.name,
|
||||
required this.address,
|
||||
required this.status,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [id, businessId, name, address, status];
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// Represents a department within a [Hub].
|
||||
///
|
||||
/// Used for more granular organization of staff and events (e.g. "Kitchen", "Service").
|
||||
class HubDepartment extends Equatable {
|
||||
/// Unique identifier.
|
||||
final String id;
|
||||
|
||||
/// The [Hub] this department belongs to.
|
||||
final String hubId;
|
||||
|
||||
/// Name of the department.
|
||||
final String name;
|
||||
|
||||
const HubDepartment({
|
||||
required this.id,
|
||||
required this.hubId,
|
||||
required this.name,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [id, hubId, name];
|
||||
}
|
||||
58
apps/packages/domain/lib/src/entities/events/assignment.dart
Normal file
58
apps/packages/domain/lib/src/entities/events/assignment.dart
Normal file
@@ -0,0 +1,58 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// The status of a staff [Assignment].
|
||||
enum AssignmentStatus {
|
||||
/// Staff member has been assigned but hasn't confirmed.
|
||||
assigned,
|
||||
|
||||
/// Staff member has accepted the assignment.
|
||||
confirmed,
|
||||
|
||||
/// Work is currently in progress (Clocked In).
|
||||
ongoing,
|
||||
|
||||
/// Work completed successfully (Clocked Out).
|
||||
completed,
|
||||
|
||||
/// Staff rejected the assignment offer.
|
||||
declinedByStaff,
|
||||
|
||||
/// Staff canceled after accepting.
|
||||
canceledByStaff,
|
||||
|
||||
/// Staff did not show up.
|
||||
noShowed,
|
||||
}
|
||||
|
||||
/// Represents the link between a [Staff] member and an [EventShiftPosition].
|
||||
class Assignment extends Equatable {
|
||||
/// Unique identifier.
|
||||
final String id;
|
||||
|
||||
/// The job position being filled.
|
||||
final String positionId;
|
||||
|
||||
/// The staff member filling the position.
|
||||
final String staffId;
|
||||
|
||||
/// Current status of the assignment.
|
||||
final AssignmentStatus status;
|
||||
|
||||
/// Actual timestamp when staff clocked in.
|
||||
final DateTime? clockIn;
|
||||
|
||||
/// Actual timestamp when staff clocked out.
|
||||
final DateTime? clockOut;
|
||||
|
||||
const Assignment({
|
||||
required this.id,
|
||||
required this.positionId,
|
||||
required this.staffId,
|
||||
required this.status,
|
||||
this.clockIn,
|
||||
this.clockOut,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [id, positionId, staffId, status, clockIn, clockOut];
|
||||
}
|
||||
70
apps/packages/domain/lib/src/entities/events/event.dart
Normal file
70
apps/packages/domain/lib/src/entities/events/event.dart
Normal file
@@ -0,0 +1,70 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// The workflow status of an [Event].
|
||||
enum EventStatus {
|
||||
/// Created but incomplete.
|
||||
draft,
|
||||
|
||||
/// Waiting for approval or publication.
|
||||
pending,
|
||||
|
||||
/// Published and staff have been assigned.
|
||||
assigned,
|
||||
|
||||
/// Fully confirmed and ready to start.
|
||||
confirmed,
|
||||
|
||||
/// Currently in progress.
|
||||
active,
|
||||
|
||||
/// Work has finished.
|
||||
finished,
|
||||
|
||||
/// All post-event processes (invoicing) complete.
|
||||
completed,
|
||||
|
||||
/// Archived.
|
||||
closed,
|
||||
|
||||
/// Flagged for administrative review.
|
||||
underReview,
|
||||
}
|
||||
|
||||
/// Represents a Job Posting or Event.
|
||||
///
|
||||
/// This is the central entity for scheduling work. An Event contains [EventShift]s.
|
||||
class Event extends Equatable {
|
||||
/// Unique identifier.
|
||||
final String id;
|
||||
|
||||
/// The [Business] hosting the event.
|
||||
final String businessId;
|
||||
|
||||
/// The [Hub] location.
|
||||
final String hubId;
|
||||
|
||||
/// Title of the event.
|
||||
final String name;
|
||||
|
||||
/// Date of the event.
|
||||
final DateTime date;
|
||||
|
||||
/// Current workflow status.
|
||||
final EventStatus status;
|
||||
|
||||
/// Type of employment contract (e.g., 'freelance', 'permanent').
|
||||
final String contractType;
|
||||
|
||||
const Event({
|
||||
required this.id,
|
||||
required this.businessId,
|
||||
required this.hubId,
|
||||
required this.name,
|
||||
required this.date,
|
||||
required this.status,
|
||||
required this.contractType,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [id, businessId, hubId, name, date, status, contractType];
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// Represents a specific time block or "shift" within an [Event].
|
||||
///
|
||||
/// An Event can have multiple shifts (e.g. "Morning Shift", "Evening Shift").
|
||||
class EventShift extends Equatable {
|
||||
/// Unique identifier.
|
||||
final String id;
|
||||
|
||||
/// The [Event] this shift belongs to.
|
||||
final String eventId;
|
||||
|
||||
/// Descriptive name (e.g. "Setup Crew").
|
||||
final String name;
|
||||
|
||||
/// Specific address for this shift (if different from Hub).
|
||||
final String address;
|
||||
|
||||
const EventShift({
|
||||
required this.id,
|
||||
required this.eventId,
|
||||
required this.name,
|
||||
required this.address,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [id, eventId, name, address];
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// Represents a specific job opening within a [EventShift].
|
||||
///
|
||||
/// Defines the requirement for a specific [Skill], the quantity needed, and the pay.
|
||||
class EventShiftPosition extends Equatable {
|
||||
/// Unique identifier.
|
||||
final String id;
|
||||
|
||||
/// The [EventShift] this position is part of.
|
||||
final String shiftId;
|
||||
|
||||
/// The [Skill] required for this position.
|
||||
final String skillId;
|
||||
|
||||
/// Number of staff needed.
|
||||
final int count;
|
||||
|
||||
/// Hourly pay rate.
|
||||
final double rate;
|
||||
|
||||
/// Start time of this specific position.
|
||||
final DateTime startTime;
|
||||
|
||||
/// End time of this specific position.
|
||||
final DateTime endTime;
|
||||
|
||||
/// Deducted break duration in minutes.
|
||||
final int breakDurationMinutes;
|
||||
|
||||
const EventShiftPosition({
|
||||
required this.id,
|
||||
required this.shiftId,
|
||||
required this.skillId,
|
||||
required this.count,
|
||||
required this.rate,
|
||||
required this.startTime,
|
||||
required this.endTime,
|
||||
required this.breakDurationMinutes,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
id,
|
||||
shiftId,
|
||||
skillId,
|
||||
count,
|
||||
rate,
|
||||
startTime,
|
||||
endTime,
|
||||
breakDurationMinutes,
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// Represents a verified record of time worked.
|
||||
///
|
||||
/// Derived from [Assignment] clock-in/out times, used for payroll.
|
||||
class WorkSession extends Equatable {
|
||||
/// Unique identifier.
|
||||
final String id;
|
||||
|
||||
/// The [Assignment] this session belongs to.
|
||||
final String assignmentId;
|
||||
|
||||
/// Verified start time.
|
||||
final DateTime startTime;
|
||||
|
||||
/// Verified end time.
|
||||
final DateTime? endTime;
|
||||
|
||||
/// Verified break duration.
|
||||
final int breakDurationMinutes;
|
||||
|
||||
const WorkSession({
|
||||
required this.id,
|
||||
required this.assignmentId,
|
||||
required this.startTime,
|
||||
this.endTime,
|
||||
required this.breakDurationMinutes,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [id, assignmentId, startTime, endTime, breakDurationMinutes];
|
||||
}
|
||||
70
apps/packages/domain/lib/src/entities/financial/invoice.dart
Normal file
70
apps/packages/domain/lib/src/entities/financial/invoice.dart
Normal file
@@ -0,0 +1,70 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// The workflow status of an [Invoice].
|
||||
enum InvoiceStatus {
|
||||
/// Generated but not yet sent/finalized.
|
||||
open,
|
||||
|
||||
/// Client has disputed a line item.
|
||||
disputed,
|
||||
|
||||
/// Dispute has been handled.
|
||||
resolved,
|
||||
|
||||
/// Invoice accepted by client.
|
||||
verified,
|
||||
|
||||
/// Payment received.
|
||||
paid,
|
||||
|
||||
/// Payment reconciled in accounting.
|
||||
reconciled,
|
||||
|
||||
/// Payment not received by due date.
|
||||
overdue,
|
||||
}
|
||||
|
||||
/// Represents a bill sent to a [Business] for services rendered.
|
||||
class Invoice extends Equatable {
|
||||
/// Unique identifier.
|
||||
final String id;
|
||||
|
||||
/// The [Event] this invoice covers.
|
||||
final String eventId;
|
||||
|
||||
/// The [Business] being billed.
|
||||
final String businessId;
|
||||
|
||||
/// Current payment/approval status.
|
||||
final InvoiceStatus status;
|
||||
|
||||
/// Grand total amount.
|
||||
final double totalAmount;
|
||||
|
||||
/// Total amount for labor costs.
|
||||
final double workAmount;
|
||||
|
||||
/// Total amount for addons/extras.
|
||||
final double addonsAmount;
|
||||
|
||||
const Invoice({
|
||||
required this.id,
|
||||
required this.eventId,
|
||||
required this.businessId,
|
||||
required this.status,
|
||||
required this.totalAmount,
|
||||
required this.workAmount,
|
||||
required this.addonsAmount,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
id,
|
||||
eventId,
|
||||
businessId,
|
||||
status,
|
||||
totalAmount,
|
||||
workAmount,
|
||||
addonsAmount,
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// Represents a reason or log for a declined [Invoice].
|
||||
class InvoiceDecline extends Equatable {
|
||||
/// Unique identifier.
|
||||
final String id;
|
||||
|
||||
/// The [Invoice] that was declined.
|
||||
final String invoiceId;
|
||||
|
||||
/// Reason provided by the client.
|
||||
final String reason;
|
||||
|
||||
/// When the decline happened.
|
||||
final DateTime declinedAt;
|
||||
|
||||
const InvoiceDecline({
|
||||
required this.id,
|
||||
required this.invoiceId,
|
||||
required this.reason,
|
||||
required this.declinedAt,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [id, invoiceId, reason, declinedAt];
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// Represents a line item in an [Invoice].
|
||||
///
|
||||
/// Corresponds to the work done by one [Staff] member.
|
||||
class InvoiceItem extends Equatable {
|
||||
/// Unique identifier.
|
||||
final String id;
|
||||
|
||||
/// The [Invoice] this item belongs to.
|
||||
final String invoiceId;
|
||||
|
||||
/// The [Staff] member whose work is being billed.
|
||||
final String staffId;
|
||||
|
||||
/// Total billed hours.
|
||||
final double workHours;
|
||||
|
||||
/// Hourly rate applied.
|
||||
final double rate;
|
||||
|
||||
/// Total line item amount (workHours * rate).
|
||||
final double amount;
|
||||
|
||||
const InvoiceItem({
|
||||
required this.id,
|
||||
required this.invoiceId,
|
||||
required this.staffId,
|
||||
required this.workHours,
|
||||
required this.rate,
|
||||
required this.amount,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [id, invoiceId, staffId, workHours, rate, amount];
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// Status of a staff payout.
|
||||
enum PaymentStatus {
|
||||
/// Payout calculated but not processed.
|
||||
pending,
|
||||
|
||||
/// Submitted to banking provider.
|
||||
processing,
|
||||
|
||||
/// Successfully transferred to staff.
|
||||
paid,
|
||||
|
||||
/// Transfer failed.
|
||||
failed,
|
||||
}
|
||||
|
||||
/// Represents a payout to a [Staff] member for a completed [Assignment].
|
||||
class StaffPayment extends Equatable {
|
||||
/// Unique identifier.
|
||||
final String id;
|
||||
|
||||
/// The recipient [Staff].
|
||||
final String staffId;
|
||||
|
||||
/// The [Assignment] being paid for.
|
||||
final String assignmentId;
|
||||
|
||||
/// Amount to be paid.
|
||||
final double amount;
|
||||
|
||||
/// Processing status.
|
||||
final PaymentStatus status;
|
||||
|
||||
/// When the payment was successfully processed.
|
||||
final DateTime? paidAt;
|
||||
|
||||
const StaffPayment({
|
||||
required this.id,
|
||||
required this.staffId,
|
||||
required this.assignmentId,
|
||||
required this.amount,
|
||||
required this.status,
|
||||
this.paidAt,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [id, staffId, assignmentId, amount, status, paidAt];
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// Represents accessibility requirements or features.
|
||||
///
|
||||
/// Can apply to Staff (needs) or Events (provision).
|
||||
class Accessibility extends Equatable {
|
||||
/// Unique identifier.
|
||||
final String id;
|
||||
|
||||
/// Description (e.g. "Wheelchair Access").
|
||||
final String name;
|
||||
|
||||
const Accessibility({
|
||||
required this.id,
|
||||
required this.name,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [id, name];
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// Represents bank account details for payroll.
|
||||
class BankAccount extends Equatable {
|
||||
/// Unique identifier.
|
||||
final String id;
|
||||
|
||||
/// The [User] owning the account.
|
||||
final String userId;
|
||||
|
||||
/// Name of the bank.
|
||||
final String bankName;
|
||||
|
||||
/// Account number.
|
||||
final String accountNumber;
|
||||
|
||||
/// Name on the account.
|
||||
final String accountName;
|
||||
|
||||
/// Sort code (if applicable).
|
||||
final String? sortCode;
|
||||
|
||||
const BankAccount({
|
||||
required this.id,
|
||||
required this.userId,
|
||||
required this.bankName,
|
||||
required this.accountNumber,
|
||||
required this.accountName,
|
||||
this.sortCode,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [id, userId, bankName, accountNumber, accountName, sortCode];
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// Represents an emergency contact for a user.
|
||||
///
|
||||
/// Critical for staff safety during shifts.
|
||||
class EmergencyContact extends Equatable {
|
||||
/// Full name of the contact.
|
||||
final String name;
|
||||
|
||||
/// Relationship to the user (e.g. "Spouse", "Parent").
|
||||
final String relationship;
|
||||
|
||||
/// Phone number.
|
||||
final String phone;
|
||||
|
||||
const EmergencyContact({
|
||||
required this.name,
|
||||
required this.relationship,
|
||||
required this.phone,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [name, relationship, phone];
|
||||
}
|
||||
32
apps/packages/domain/lib/src/entities/profile/schedule.dart
Normal file
32
apps/packages/domain/lib/src/entities/profile/schedule.dart
Normal file
@@ -0,0 +1,32 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// Represents general availability schedule for a [Staff] member.
|
||||
///
|
||||
/// Defines recurring availability (e.g., "Mondays 9-5").
|
||||
class Schedule extends Equatable {
|
||||
/// Unique identifier.
|
||||
final String id;
|
||||
|
||||
/// The [Staff] member.
|
||||
final String staffId;
|
||||
|
||||
/// Day of the week (1 = Monday, 7 = Sunday).
|
||||
final int dayOfWeek;
|
||||
|
||||
/// Start time of availability.
|
||||
final DateTime startTime;
|
||||
|
||||
/// End time of availability.
|
||||
final DateTime endTime;
|
||||
|
||||
const Schedule({
|
||||
required this.id,
|
||||
required this.staffId,
|
||||
required this.dayOfWeek,
|
||||
required this.startTime,
|
||||
required this.endTime,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [id, staffId, dayOfWeek, startTime, endTime];
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// The type of preference a business has for a staff member.
|
||||
enum PreferenceType {
|
||||
/// Business wants to prioritize this staff member.
|
||||
favorite,
|
||||
|
||||
/// Business does not want to work with this staff member.
|
||||
blocked,
|
||||
}
|
||||
|
||||
/// Represents a business's specific preference for a staff member.
|
||||
class BusinessStaffPreference extends Equatable {
|
||||
/// Unique identifier.
|
||||
final String id;
|
||||
|
||||
/// The [Business] holding the preference.
|
||||
final String businessId;
|
||||
|
||||
/// The [Staff] member.
|
||||
final String staffId;
|
||||
|
||||
/// Whether they are a favorite or blocked.
|
||||
final PreferenceType type;
|
||||
|
||||
const BusinessStaffPreference({
|
||||
required this.id,
|
||||
required this.businessId,
|
||||
required this.staffId,
|
||||
required this.type,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [id, businessId, staffId, type];
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// Represents a penalty issued to a staff member.
|
||||
///
|
||||
/// Penalties are issued for no-shows, cancellations, or poor conduct.
|
||||
class PenaltyLog extends Equatable {
|
||||
/// Unique identifier.
|
||||
final String id;
|
||||
|
||||
/// The [Staff] member penalized.
|
||||
final String staffId;
|
||||
|
||||
/// The [Assignment] context (if applicable).
|
||||
final String assignmentId;
|
||||
|
||||
/// Reason for the penalty.
|
||||
final String reason;
|
||||
|
||||
/// Score points deducted from staff profile.
|
||||
final int points;
|
||||
|
||||
/// When the penalty was issued.
|
||||
final DateTime issuedAt;
|
||||
|
||||
const PenaltyLog({
|
||||
required this.id,
|
||||
required this.staffId,
|
||||
required this.assignmentId,
|
||||
required this.reason,
|
||||
required this.points,
|
||||
required this.issuedAt,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [id, staffId, assignmentId, reason, points, issuedAt];
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// Represents a rating given to a staff member by a client.
|
||||
class StaffRating extends Equatable {
|
||||
/// Unique identifier.
|
||||
final String id;
|
||||
|
||||
/// The [Staff] being rated.
|
||||
final String staffId;
|
||||
|
||||
/// The [Event] context.
|
||||
final String eventId;
|
||||
|
||||
/// The [Business] leaving the rating.
|
||||
final String businessId;
|
||||
|
||||
/// Star rating (1-5).
|
||||
final int rating;
|
||||
|
||||
/// Optional feedback text.
|
||||
final String? comment;
|
||||
|
||||
const StaffRating({
|
||||
required this.id,
|
||||
required this.staffId,
|
||||
required this.eventId,
|
||||
required this.businessId,
|
||||
required this.rating,
|
||||
this.comment,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [id, staffId, eventId, businessId, rating, comment];
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// Represents a required certificate definition.
|
||||
///
|
||||
/// Examples: "Food Hygiene Level 2", "SIA Badge".
|
||||
class Certificate extends Equatable {
|
||||
/// Unique identifier.
|
||||
final String id;
|
||||
|
||||
/// Display name of the certificate.
|
||||
final String name;
|
||||
|
||||
/// Whether this certificate is mandatory for platform access or specific roles.
|
||||
final bool isRequired;
|
||||
|
||||
const Certificate({
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.isRequired,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [id, name, isRequired];
|
||||
}
|
||||
29
apps/packages/domain/lib/src/entities/skills/skill.dart
Normal file
29
apps/packages/domain/lib/src/entities/skills/skill.dart
Normal file
@@ -0,0 +1,29 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// Represents a job category / skill type.
|
||||
///
|
||||
/// Examples: "Waiter", "Security Guard", "Bartender".
|
||||
/// Linked to a [SkillCategory].
|
||||
class Skill extends Equatable {
|
||||
/// Unique identifier.
|
||||
final String id;
|
||||
|
||||
/// The broader category (e.g. "Hospitality").
|
||||
final String categoryId;
|
||||
|
||||
/// Display name of the skill.
|
||||
final String name;
|
||||
|
||||
/// Default hourly rate suggested for this skill.
|
||||
final double basePrice;
|
||||
|
||||
const Skill({
|
||||
required this.id,
|
||||
required this.categoryId,
|
||||
required this.name,
|
||||
required this.basePrice,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [id, categoryId, name, basePrice];
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// Represents a broad category of skills (e.g. "Hospitality", "Logistics").
|
||||
class SkillCategory extends Equatable {
|
||||
/// Unique identifier.
|
||||
final String id;
|
||||
|
||||
/// Display name.
|
||||
final String name;
|
||||
|
||||
const SkillCategory({
|
||||
required this.id,
|
||||
required this.name,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [id, name];
|
||||
}
|
||||
32
apps/packages/domain/lib/src/entities/skills/skill_kit.dart
Normal file
32
apps/packages/domain/lib/src/entities/skills/skill_kit.dart
Normal file
@@ -0,0 +1,32 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// Represents required equipment or uniform for a specific [Skill].
|
||||
///
|
||||
/// Examples: "Black Shirt" (Uniform), "Safety Boots" (Equipment).
|
||||
class SkillKit extends Equatable {
|
||||
/// Unique identifier.
|
||||
final String id;
|
||||
|
||||
/// The [Skill] this kit applies to.
|
||||
final String skillId;
|
||||
|
||||
/// Description of the item.
|
||||
final String name;
|
||||
|
||||
/// Whether the staff member MUST possess this item.
|
||||
final bool isRequired;
|
||||
|
||||
/// Type of kit ('uniform' or 'equipment').
|
||||
final String type;
|
||||
|
||||
const SkillKit({
|
||||
required this.id,
|
||||
required this.skillId,
|
||||
required this.name,
|
||||
required this.isRequired,
|
||||
required this.type,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [id, skillId, name, isRequired, type];
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// The expertise level of a staff member in a specific skill.
|
||||
enum SkillLevel {
|
||||
/// Entry level.
|
||||
beginner,
|
||||
|
||||
/// Experienced.
|
||||
skilled,
|
||||
|
||||
/// Expert / Managerial level.
|
||||
professional,
|
||||
}
|
||||
|
||||
/// The verification status of a claimed skill.
|
||||
enum StaffSkillStatus {
|
||||
/// Claimed by staff, waiting for admin approval.
|
||||
pending,
|
||||
|
||||
/// Verified by admin (documents checked).
|
||||
verified,
|
||||
|
||||
/// Rejected by admin.
|
||||
rejected,
|
||||
}
|
||||
|
||||
/// Represents a staff member's qualification in a specific [Skill].
|
||||
class StaffSkill extends Equatable {
|
||||
/// Unique identifier.
|
||||
final String id;
|
||||
|
||||
/// The [Staff] member.
|
||||
final String staffId;
|
||||
|
||||
/// The [Skill] they possess.
|
||||
final String skillId;
|
||||
|
||||
/// Their expertise level.
|
||||
final SkillLevel level;
|
||||
|
||||
/// Years of experience.
|
||||
final int experienceYears;
|
||||
|
||||
/// Verification status.
|
||||
final StaffSkillStatus status;
|
||||
|
||||
const StaffSkill({
|
||||
required this.id,
|
||||
required this.staffId,
|
||||
required this.skillId,
|
||||
required this.level,
|
||||
required this.experienceYears,
|
||||
required this.status,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [id, staffId, skillId, level, experienceYears, status];
|
||||
}
|
||||
26
apps/packages/domain/lib/src/entities/support/addon.dart
Normal file
26
apps/packages/domain/lib/src/entities/support/addon.dart
Normal file
@@ -0,0 +1,26 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// Represents a financial addon/bonus/deduction applied to an Invoice or Payment.
|
||||
class Addon extends Equatable {
|
||||
/// Unique identifier.
|
||||
final String id;
|
||||
|
||||
/// Description (e.g. "Travel Expense").
|
||||
final String name;
|
||||
|
||||
/// Monetary value.
|
||||
final double amount;
|
||||
|
||||
/// Type ('credit' or 'debit').
|
||||
final String type;
|
||||
|
||||
const Addon({
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.amount,
|
||||
required this.type,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [id, name, amount, type];
|
||||
}
|
||||
24
apps/packages/domain/lib/src/entities/support/media.dart
Normal file
24
apps/packages/domain/lib/src/entities/support/media.dart
Normal file
@@ -0,0 +1,24 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// Represents a media file reference.
|
||||
///
|
||||
/// Used for avatars, certificates, or event photos.
|
||||
class Media extends Equatable {
|
||||
/// Unique identifier.
|
||||
final String id;
|
||||
|
||||
/// External URL to the file.
|
||||
final String url;
|
||||
|
||||
/// MIME type or general type (image, pdf).
|
||||
final String type;
|
||||
|
||||
const Media({
|
||||
required this.id,
|
||||
required this.url,
|
||||
required this.type,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [id, url, type];
|
||||
}
|
||||
18
apps/packages/domain/lib/src/entities/support/tag.dart
Normal file
18
apps/packages/domain/lib/src/entities/support/tag.dart
Normal file
@@ -0,0 +1,18 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// Represents a descriptive tag used for categorizing events or staff.
|
||||
class Tag extends Equatable {
|
||||
/// Unique identifier.
|
||||
final String id;
|
||||
|
||||
/// Text label.
|
||||
final String label;
|
||||
|
||||
const Tag({
|
||||
required this.id,
|
||||
required this.label,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [id, label];
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// Represents a geographical area where a [Staff] member is willing to work.
|
||||
class WorkingArea extends Equatable {
|
||||
/// Unique identifier.
|
||||
final String id;
|
||||
|
||||
/// Name of the area (e.g. "London Zone 1").
|
||||
final String name;
|
||||
|
||||
/// Latitude of the center point.
|
||||
final double centerLat;
|
||||
|
||||
/// Longitude of the center point.
|
||||
final double centerLng;
|
||||
|
||||
/// Radius in Kilometers.
|
||||
final double radiusKm;
|
||||
|
||||
const WorkingArea({
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.centerLat,
|
||||
required this.centerLng,
|
||||
required this.radiusKm,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [id, name, centerLat, centerLng, radiusKm];
|
||||
}
|
||||
28
apps/packages/domain/lib/src/entities/users/biz_member.dart
Normal file
28
apps/packages/domain/lib/src/entities/users/biz_member.dart
Normal file
@@ -0,0 +1,28 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// Represents a member of a Business.
|
||||
///
|
||||
/// Grants a user access to business-level operations.
|
||||
class BizMember extends Equatable {
|
||||
/// Unique identifier for this membership.
|
||||
final String id;
|
||||
|
||||
/// The [Business] the user belongs to.
|
||||
final String businessId;
|
||||
|
||||
/// The [User] who is a member.
|
||||
final String userId;
|
||||
|
||||
/// The role within the business.
|
||||
final String role;
|
||||
|
||||
const BizMember({
|
||||
required this.id,
|
||||
required this.businessId,
|
||||
required this.userId,
|
||||
required this.role,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [id, businessId, userId, role];
|
||||
}
|
||||
28
apps/packages/domain/lib/src/entities/users/hub_member.dart
Normal file
28
apps/packages/domain/lib/src/entities/users/hub_member.dart
Normal file
@@ -0,0 +1,28 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// Represents a member of a Hub.
|
||||
///
|
||||
/// Grants a user access to specific [Hub] operations, distinct from [BizMember].
|
||||
class HubMember extends Equatable {
|
||||
/// Unique identifier for this membership.
|
||||
final String id;
|
||||
|
||||
/// The [Hub] the user belongs to.
|
||||
final String hubId;
|
||||
|
||||
/// The [User] who is a member.
|
||||
final String userId;
|
||||
|
||||
/// The role within the hub.
|
||||
final String role;
|
||||
|
||||
const HubMember({
|
||||
required this.id,
|
||||
required this.hubId,
|
||||
required this.userId,
|
||||
required this.role,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [id, hubId, userId, role];
|
||||
}
|
||||
32
apps/packages/domain/lib/src/entities/users/membership.dart
Normal file
32
apps/packages/domain/lib/src/entities/users/membership.dart
Normal file
@@ -0,0 +1,32 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// Represents a polymorphic membership to an organization unit.
|
||||
///
|
||||
/// Allows a [User] to be a member of either a [Business] or a [Hub].
|
||||
class Membership extends Equatable {
|
||||
/// Unique identifier for the membership record.
|
||||
final String id;
|
||||
|
||||
/// The [User] holding this membership.
|
||||
final String userId;
|
||||
|
||||
/// The ID of the organization unit (Business or Hub).
|
||||
final String memberableId;
|
||||
|
||||
/// The type of the organization unit ('business' or 'hub').
|
||||
final String memberableType;
|
||||
|
||||
/// The role within that organization (e.g., 'manager', 'viewer').
|
||||
final String role;
|
||||
|
||||
const Membership({
|
||||
required this.id,
|
||||
required this.userId,
|
||||
required this.memberableId,
|
||||
required this.memberableType,
|
||||
required this.role,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [id, userId, memberableId, memberableType, role];
|
||||
}
|
||||
83
apps/packages/domain/lib/src/entities/users/staff.dart
Normal file
83
apps/packages/domain/lib/src/entities/users/staff.dart
Normal file
@@ -0,0 +1,83 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// The lifecycle status of a [Staff] account.
|
||||
enum StaffStatus {
|
||||
/// Account created but profile not started.
|
||||
registered,
|
||||
|
||||
/// Profile submitted and awaiting verification.
|
||||
pending,
|
||||
|
||||
/// Profile information filled but not submitted for verification.
|
||||
completedProfile,
|
||||
|
||||
/// Profile verified by admin.
|
||||
verified,
|
||||
|
||||
/// Staff is currently active and eligible for work.
|
||||
active,
|
||||
|
||||
/// Account is temporarily suspended.
|
||||
blocked,
|
||||
|
||||
/// Account is permanently inactive.
|
||||
inactive,
|
||||
}
|
||||
|
||||
/// Represents a worker profile.
|
||||
///
|
||||
/// Contains all personal and professional details of a staff member.
|
||||
/// Linked to a [User] via [authProviderId].
|
||||
class Staff extends Equatable {
|
||||
/// Unique identifier for the staff profile.
|
||||
final String id;
|
||||
|
||||
/// Link to the [User] authentication record.
|
||||
final String authProviderId;
|
||||
|
||||
/// Full display name.
|
||||
final String name;
|
||||
|
||||
/// Contact email.
|
||||
final String email;
|
||||
|
||||
/// Contact phone number.
|
||||
final String? phone;
|
||||
|
||||
/// Current workflow status of the staff member.
|
||||
final StaffStatus status;
|
||||
|
||||
/// Physical address string.
|
||||
final String? address;
|
||||
|
||||
/// URL to the avatar image.
|
||||
final String? avatar;
|
||||
|
||||
/// URL to a verified live photo for identity verification.
|
||||
final String? livePhoto;
|
||||
|
||||
const Staff({
|
||||
required this.id,
|
||||
required this.authProviderId,
|
||||
required this.name,
|
||||
required this.email,
|
||||
this.phone,
|
||||
required this.status,
|
||||
this.address,
|
||||
this.avatar,
|
||||
this.livePhoto,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
id,
|
||||
authProviderId,
|
||||
name,
|
||||
email,
|
||||
phone,
|
||||
status,
|
||||
address,
|
||||
avatar,
|
||||
livePhoto,
|
||||
];
|
||||
}
|
||||
30
apps/packages/domain/lib/src/entities/users/user.dart
Normal file
30
apps/packages/domain/lib/src/entities/users/user.dart
Normal file
@@ -0,0 +1,30 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// Represents a base authenticated user in the KROW platform.
|
||||
///
|
||||
/// This entity corresponds to the Firebase Auth user record and acts as the
|
||||
/// linkage between the authentication system and the specific [Staff] or Client profiles.
|
||||
class User extends Equatable {
|
||||
/// The unique identifier from the authentication provider (e.g., Firebase UID).
|
||||
final String id;
|
||||
|
||||
/// The user's email address.
|
||||
final String email;
|
||||
|
||||
/// The user's phone number, if available.
|
||||
final String? phone;
|
||||
|
||||
/// The primary role of the user (e.g., 'staff', 'client_admin').
|
||||
/// This determines the initial routing and permissions.
|
||||
final String role;
|
||||
|
||||
const User({
|
||||
required this.id,
|
||||
required this.email,
|
||||
this.phone,
|
||||
required this.role,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [id, email, phone, role];
|
||||
}
|
||||
11
apps/packages/domain/pubspec.yaml
Normal file
11
apps/packages/domain/pubspec.yaml
Normal file
@@ -0,0 +1,11 @@
|
||||
name: krow_domain
|
||||
description: Domain entities and business logic.
|
||||
version: 0.0.1
|
||||
publish_to: none
|
||||
resolution: workspace
|
||||
|
||||
environment:
|
||||
sdk: '>=3.10.0 <4.0.0'
|
||||
|
||||
dependencies:
|
||||
equatable: ^2.0.8
|
||||
0
apps/packages/features/.gitkeep
Normal file
0
apps/packages/features/.gitkeep
Normal file
@@ -0,0 +1,63 @@
|
||||
library client_authentication;
|
||||
|
||||
import 'package:flutter_modular/flutter_modular.dart';
|
||||
import 'package:krow_data_connect/krow_data_connect.dart';
|
||||
import 'src/data/repositories_impl/auth_repository_impl.dart';
|
||||
import 'src/domain/repositories/auth_repository_interface.dart';
|
||||
import 'src/domain/usecases/sign_in_with_email_use_case.dart';
|
||||
import 'src/domain/usecases/sign_in_with_social_use_case.dart';
|
||||
import 'src/domain/usecases/sign_out_use_case.dart';
|
||||
import 'src/domain/usecases/sign_up_with_email_use_case.dart';
|
||||
import 'src/presentation/blocs/client_auth_bloc.dart';
|
||||
import 'src/presentation/pages/client_get_started_page.dart';
|
||||
import 'src/presentation/pages/client_sign_in_page.dart';
|
||||
import 'src/presentation/pages/client_sign_up_page.dart';
|
||||
|
||||
export 'src/presentation/pages/client_get_started_page.dart';
|
||||
export 'src/presentation/pages/client_sign_in_page.dart';
|
||||
export 'src/presentation/pages/client_sign_up_page.dart';
|
||||
export 'src/presentation/navigation/client_auth_navigator.dart';
|
||||
export 'package:core_localization/core_localization.dart';
|
||||
|
||||
/// A [Module] for the client authentication feature.
|
||||
class ClientAuthenticationModule extends Module {
|
||||
@override
|
||||
List<Module> get imports => [DataConnectModule()];
|
||||
|
||||
@override
|
||||
void binds(Injector i) {
|
||||
// Repositories
|
||||
i.addLazySingleton<AuthRepositoryInterface>(
|
||||
() => AuthRepositoryImpl(dataSource: i.get<AuthRepositoryMock>()),
|
||||
);
|
||||
|
||||
// UseCases
|
||||
i.addLazySingleton(
|
||||
() => SignInWithEmailUseCase(i.get<AuthRepositoryInterface>()),
|
||||
);
|
||||
i.addLazySingleton(
|
||||
() => SignUpWithEmailUseCase(i.get<AuthRepositoryInterface>()),
|
||||
);
|
||||
i.addLazySingleton(
|
||||
() => SignInWithSocialUseCase(i.get<AuthRepositoryInterface>()),
|
||||
);
|
||||
i.addLazySingleton(() => SignOutUseCase(i.get<AuthRepositoryInterface>()));
|
||||
|
||||
// BLoCs
|
||||
i.addLazySingleton<ClientAuthBloc>(
|
||||
() => ClientAuthBloc(
|
||||
signInWithEmail: i.get<SignInWithEmailUseCase>(),
|
||||
signUpWithEmail: i.get<SignUpWithEmailUseCase>(),
|
||||
signInWithSocial: i.get<SignInWithSocialUseCase>(),
|
||||
signOut: i.get<SignOutUseCase>(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void routes(r) {
|
||||
r.child('/', child: (_) => const ClientGetStartedPage());
|
||||
r.child('/client-sign-in', child: (_) => const ClientSignInPage());
|
||||
r.child('/client-sign-up', child: (_) => const ClientSignUpPage());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import 'package:krow_data_connect/krow_data_connect.dart';
|
||||
import 'package:krow_domain/krow_domain.dart';
|
||||
|
||||
import '../../domain/repositories/auth_repository_interface.dart';
|
||||
|
||||
/// Production-ready implementation of the [AuthRepositoryInterface].
|
||||
///
|
||||
/// This implementation integrates with the [krow_data_connect] package to provide
|
||||
/// authentication services. It delegates actual data operations to the
|
||||
/// [AuthRepositoryMock] (or eventually the real implementation) injected from the app layer.
|
||||
class AuthRepositoryImpl implements AuthRepositoryInterface {
|
||||
/// The data source used for authentication operations.
|
||||
final AuthRepositoryMock _dataSource;
|
||||
|
||||
/// Creates an [AuthRepositoryImpl] with the injected [dataSource] dependency.
|
||||
AuthRepositoryImpl({required AuthRepositoryMock dataSource})
|
||||
: _dataSource = dataSource;
|
||||
|
||||
@override
|
||||
Future<User> signInWithEmail({
|
||||
required String email,
|
||||
required String password,
|
||||
}) {
|
||||
return _dataSource.signInWithEmail(email, password);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<User> signUpWithEmail({
|
||||
required String companyName,
|
||||
required String email,
|
||||
required String password,
|
||||
}) {
|
||||
return _dataSource.signUpWithEmail(email, password, companyName);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<User> signInWithSocial({required String provider}) {
|
||||
return _dataSource.signInWithSocial(provider);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> signOut() => _dataSource.signOut();
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import 'package:krow_core/core.dart';
|
||||
|
||||
/// Arguments for the [SignInWithEmailUseCase].
|
||||
class SignInWithEmailArguments extends UseCaseArgument {
|
||||
/// The user's email address.
|
||||
final String email;
|
||||
|
||||
/// The user's password.
|
||||
final String password;
|
||||
|
||||
const SignInWithEmailArguments({required this.email, required this.password});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [email, password];
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import 'package:krow_core/core.dart';
|
||||
|
||||
/// Arguments for the [SignInWithSocialUseCase].
|
||||
class SignInWithSocialArguments extends UseCaseArgument {
|
||||
/// The social provider name (e.g. 'google' or 'apple').
|
||||
final String provider;
|
||||
|
||||
const SignInWithSocialArguments({required this.provider});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [provider];
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user