Add initial mobile app prototypes and staff payments feature
Introduces the first versions of client and staff mobile application prototypes, including platform-specific assets, screens, and configuration for Android, iOS, macOS, Linux, and Windows. Adds documentation, AI prompt guides, and a new staff payments feature module with repository, use cases, and presentation logic. Also includes generated localization files and supporting resources for both client and staff apps.
This commit is contained in:
@@ -0,0 +1,183 @@
|
||||
/// Generated file. Do not edit.
|
||||
///
|
||||
/// Source: lib/src/l10n
|
||||
/// To regenerate, run: `dart run slang`
|
||||
///
|
||||
/// Locales: 2
|
||||
/// Strings: 1004 (502 per locale)
|
||||
///
|
||||
/// Built on 2026-01-25 at 22:00 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;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,15 @@
|
||||
import 'package:krow_data_connect/krow_data_connect.dart';
|
||||
import 'package:krow_domain/krow_domain.dart';
|
||||
import '../../domain/repositories/payments_repository.dart';
|
||||
|
||||
class PaymentsRepositoryImpl implements PaymentsRepository {
|
||||
final FinancialRepositoryMock financialRepository;
|
||||
|
||||
PaymentsRepositoryImpl({required this.financialRepository});
|
||||
|
||||
@override
|
||||
Future<List<StaffPayment>> getPayments() async {
|
||||
// TODO: Get actual logged in staff ID
|
||||
return await financialRepository.getStaffPayments('staff_1');
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
<<<<<<< Updated upstream
|
||||
import '../entities/payment_summary.dart';
|
||||
import '../entities/payment_transaction.dart';
|
||||
|
||||
@@ -7,4 +8,11 @@ abstract class PaymentsRepository {
|
||||
|
||||
/// Fetches the list of recent payment transactions (history).
|
||||
Future<List<PaymentTransaction>> getPaymentHistory(String period);
|
||||
=======
|
||||
import 'package:krow_domain/krow_domain.dart';
|
||||
|
||||
abstract class PaymentsRepository {
|
||||
/// Fetches the list of payments.
|
||||
Future<List<StaffPayment>> getPayments();
|
||||
>>>>>>> Stashed changes
|
||||
}
|
||||
|
||||
@@ -1,12 +1,27 @@
|
||||
<<<<<<< Updated upstream
|
||||
import '../entities/payment_transaction.dart';
|
||||
import '../repositories/payments_repository.dart';
|
||||
|
||||
class GetPaymentHistoryUseCase {
|
||||
=======
|
||||
import 'package:krow_core/core.dart';
|
||||
import 'package:krow_domain/krow_domain.dart';
|
||||
import '../repositories/payments_repository.dart';
|
||||
|
||||
class GetPaymentHistoryUseCase extends UseCase<String, List<StaffPayment>> {
|
||||
>>>>>>> Stashed changes
|
||||
final PaymentsRepository repository;
|
||||
|
||||
GetPaymentHistoryUseCase(this.repository);
|
||||
|
||||
<<<<<<< Updated upstream
|
||||
Future<List<PaymentTransaction>> call({String period = 'week'}) async {
|
||||
return await repository.getPaymentHistory(period);
|
||||
=======
|
||||
@override
|
||||
Future<List<StaffPayment>> call(String period) async {
|
||||
// TODO: Implement filtering by period
|
||||
return await repository.getPayments();
|
||||
>>>>>>> Stashed changes
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,26 @@
|
||||
<<<<<<< Updated upstream
|
||||
import '../entities/payment_summary.dart';
|
||||
import '../repositories/payments_repository.dart';
|
||||
|
||||
class GetPaymentSummaryUseCase {
|
||||
=======
|
||||
import 'package:krow_core/core.dart';
|
||||
import 'package:krow_domain/krow_domain.dart';
|
||||
import '../repositories/payments_repository.dart';
|
||||
|
||||
class GetPaymentSummaryUseCase extends NoInputUseCase<List<StaffPayment>> {
|
||||
>>>>>>> Stashed changes
|
||||
final PaymentsRepository repository;
|
||||
|
||||
GetPaymentSummaryUseCase(this.repository);
|
||||
|
||||
<<<<<<< Updated upstream
|
||||
Future<PaymentSummary> call() async {
|
||||
return await repository.getPaymentSummary();
|
||||
=======
|
||||
@override
|
||||
Future<List<StaffPayment>> call() async {
|
||||
return await repository.getPayments();
|
||||
>>>>>>> Stashed changes
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,31 @@
|
||||
import 'package:flutter_modular/flutter_modular.dart';
|
||||
<<<<<<< Updated upstream
|
||||
import 'domain/repositories/payments_repository.dart';
|
||||
import 'domain/usecases/get_payment_summary_usecase.dart';
|
||||
import 'domain/usecases/get_payment_history_usecase.dart';
|
||||
import 'data/datasources/payments_remote_datasource.dart';
|
||||
import 'data/datasources/payments_mock_datasource.dart';
|
||||
import 'data/repositories/payments_repository_impl.dart';
|
||||
=======
|
||||
import 'package:krow_data_connect/krow_data_connect.dart';
|
||||
import 'domain/repositories/payments_repository.dart';
|
||||
import 'domain/usecases/get_payment_summary_usecase.dart';
|
||||
import 'domain/usecases/get_payment_history_usecase.dart';
|
||||
import 'data/repositories_impl/payments_repository_impl.dart';
|
||||
>>>>>>> Stashed changes
|
||||
import 'presentation/blocs/payments/payments_bloc.dart';
|
||||
import 'presentation/pages/payments_page.dart';
|
||||
|
||||
class StaffPaymentsModule extends Module {
|
||||
@override
|
||||
void binds(Injector i) {
|
||||
<<<<<<< Updated upstream
|
||||
// Data Sources
|
||||
i.add<PaymentsRemoteDataSource>(PaymentsMockDataSource.new);
|
||||
=======
|
||||
// Data Connect Mocks
|
||||
i.add<FinancialRepositoryMock>(FinancialRepositoryMock.new);
|
||||
>>>>>>> Stashed changes
|
||||
|
||||
// Repositories
|
||||
i.add<PaymentsRepository>(PaymentsRepositoryImpl.new);
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
<<<<<<< Updated upstream
|
||||
import '../../../domain/entities/payment_summary.dart';
|
||||
import '../../../domain/entities/payment_transaction.dart';
|
||||
import '../../../domain/usecases/get_payment_summary_usecase.dart';
|
||||
import '../../../domain/usecases/get_payment_history_usecase.dart';
|
||||
=======
|
||||
import 'package:krow_domain/krow_domain.dart';
|
||||
import '../../../domain/usecases/get_payment_summary_usecase.dart';
|
||||
import '../../../domain/usecases/get_payment_history_usecase.dart';
|
||||
import '../../models/payment_stats.dart';
|
||||
>>>>>>> Stashed changes
|
||||
import 'payments_event.dart';
|
||||
import 'payments_state.dart';
|
||||
|
||||
@@ -24,10 +31,19 @@ class PaymentsBloc extends Bloc<PaymentsEvent, PaymentsState> {
|
||||
) async {
|
||||
emit(PaymentsLoading());
|
||||
try {
|
||||
<<<<<<< Updated upstream
|
||||
final PaymentSummary summary = await getPaymentSummary();
|
||||
final List<PaymentTransaction> history = await getPaymentHistory(period: 'week');
|
||||
emit(PaymentsLoaded(
|
||||
summary: summary,
|
||||
=======
|
||||
final List<StaffPayment> allPayments = await getPaymentSummary();
|
||||
final PaymentStats stats = _calculateStats(allPayments);
|
||||
|
||||
final List<StaffPayment> history = await getPaymentHistory('week');
|
||||
emit(PaymentsLoaded(
|
||||
summary: stats,
|
||||
>>>>>>> Stashed changes
|
||||
history: history,
|
||||
activePeriod: 'week',
|
||||
));
|
||||
@@ -44,10 +60,15 @@ class PaymentsBloc extends Bloc<PaymentsEvent, PaymentsState> {
|
||||
if (currentState is PaymentsLoaded) {
|
||||
if (currentState.activePeriod == event.period) return;
|
||||
|
||||
<<<<<<< Updated upstream
|
||||
// Optimistic update or set loading state if expecting delay
|
||||
// For now, we'll keep the current data and fetch new history
|
||||
try {
|
||||
final List<PaymentTransaction> newHistory = await getPaymentHistory(period: event.period);
|
||||
=======
|
||||
try {
|
||||
final List<StaffPayment> newHistory = await getPaymentHistory(event.period);
|
||||
>>>>>>> Stashed changes
|
||||
emit(currentState.copyWith(
|
||||
history: newHistory,
|
||||
activePeriod: event.period,
|
||||
@@ -57,4 +78,41 @@ class PaymentsBloc extends Bloc<PaymentsEvent, PaymentsState> {
|
||||
}
|
||||
}
|
||||
}
|
||||
<<<<<<< Updated upstream
|
||||
=======
|
||||
|
||||
PaymentStats _calculateStats(List<StaffPayment> payments) {
|
||||
double total = 0;
|
||||
double pending = 0;
|
||||
double weekly = 0;
|
||||
double monthly = 0;
|
||||
|
||||
final DateTime now = DateTime.now();
|
||||
|
||||
for (final StaffPayment p in payments) {
|
||||
// Assuming all payments count towards total history
|
||||
total += p.amount;
|
||||
|
||||
if (p.status == PaymentStatus.pending) {
|
||||
pending += p.amount;
|
||||
}
|
||||
|
||||
if (p.paidAt != null) {
|
||||
if (now.difference(p.paidAt!).inDays < 7) {
|
||||
weekly += p.amount;
|
||||
}
|
||||
if (now.month == p.paidAt!.month && now.year == p.paidAt!.year) {
|
||||
monthly += p.amount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return PaymentStats(
|
||||
totalEarnings: total,
|
||||
pendingEarnings: pending,
|
||||
weeklyEarnings: weekly,
|
||||
monthlyEarnings: monthly,
|
||||
);
|
||||
}
|
||||
>>>>>>> Stashed changes
|
||||
}
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
<<<<<<< Updated upstream
|
||||
import '../../../domain/entities/payment_summary.dart';
|
||||
import '../../../domain/entities/payment_transaction.dart';
|
||||
=======
|
||||
import 'package:krow_domain/krow_domain.dart';
|
||||
import '../../models/payment_stats.dart';
|
||||
>>>>>>> Stashed changes
|
||||
|
||||
abstract class PaymentsState extends Equatable {
|
||||
const PaymentsState();
|
||||
@@ -14,8 +19,13 @@ class PaymentsInitial extends PaymentsState {}
|
||||
class PaymentsLoading extends PaymentsState {}
|
||||
|
||||
class PaymentsLoaded extends PaymentsState {
|
||||
<<<<<<< Updated upstream
|
||||
final PaymentSummary summary;
|
||||
final List<PaymentTransaction> history;
|
||||
=======
|
||||
final PaymentStats summary;
|
||||
final List<StaffPayment> history;
|
||||
>>>>>>> Stashed changes
|
||||
final String activePeriod;
|
||||
|
||||
const PaymentsLoaded({
|
||||
@@ -25,8 +35,13 @@ class PaymentsLoaded extends PaymentsState {
|
||||
});
|
||||
|
||||
PaymentsLoaded copyWith({
|
||||
<<<<<<< Updated upstream
|
||||
PaymentSummary? summary,
|
||||
List<PaymentTransaction>? history,
|
||||
=======
|
||||
PaymentStats? summary,
|
||||
List<StaffPayment>? history,
|
||||
>>>>>>> Stashed changes
|
||||
String? activePeriod,
|
||||
}) {
|
||||
return PaymentsLoaded(
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
class PaymentStats extends Equatable {
|
||||
final double weeklyEarnings;
|
||||
final double monthlyEarnings;
|
||||
final double pendingEarnings;
|
||||
final double totalEarnings;
|
||||
|
||||
const PaymentStats({
|
||||
this.weeklyEarnings = 0.0,
|
||||
this.monthlyEarnings = 0.0,
|
||||
this.pendingEarnings = 0.0,
|
||||
this.totalEarnings = 0.0,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
weeklyEarnings,
|
||||
monthlyEarnings,
|
||||
pendingEarnings,
|
||||
totalEarnings,
|
||||
];
|
||||
}
|
||||
@@ -3,7 +3,11 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_modular/flutter_modular.dart';
|
||||
import 'package:lucide_icons/lucide_icons.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
<<<<<<< Updated upstream
|
||||
import '../../domain/entities/payment_transaction.dart';
|
||||
=======
|
||||
import 'package:krow_domain/krow_domain.dart';
|
||||
>>>>>>> Stashed changes
|
||||
import '../blocs/payments/payments_bloc.dart';
|
||||
import '../blocs/payments/payments_event.dart';
|
||||
import '../blocs/payments/payments_state.dart';
|
||||
@@ -177,11 +181,16 @@ class _PaymentsPageState extends State<PaymentsPage> {
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Column(
|
||||
<<<<<<< Updated upstream
|
||||
children: state.history.map((PaymentTransaction payment) {
|
||||
=======
|
||||
children: state.history.map((StaffPayment payment) {
|
||||
>>>>>>> Stashed changes
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8),
|
||||
child: PaymentHistoryItem(
|
||||
amount: payment.amount,
|
||||
<<<<<<< Updated upstream
|
||||
title: payment.title,
|
||||
location: payment.location,
|
||||
address: payment.address,
|
||||
@@ -190,6 +199,16 @@ class _PaymentsPageState extends State<PaymentsPage> {
|
||||
hours: payment.hours,
|
||||
rate: payment.rate,
|
||||
status: payment.status,
|
||||
=======
|
||||
title: 'Assignment ${payment.assignmentId}',
|
||||
location: 'Location', // TODO: Fetch from assignment
|
||||
address: '',
|
||||
date: payment.paidAt != null ? DateFormat('E, MMM d').format(payment.paidAt!) : 'Pending',
|
||||
workedTime: '00:00 - 00:00', // TODO: Fetch from assignment
|
||||
hours: 0,
|
||||
rate: 0,
|
||||
status: payment.status.toString().split('.').last,
|
||||
>>>>>>> Stashed changes
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
|
||||
@@ -2,9 +2,16 @@ name: staff_payments
|
||||
description: Staff Payments feature
|
||||
version: 0.0.1
|
||||
publish_to: 'none'
|
||||
<<<<<<< Updated upstream
|
||||
|
||||
environment:
|
||||
sdk: '>=3.0.0 <4.0.0'
|
||||
=======
|
||||
resolution: workspace
|
||||
|
||||
environment:
|
||||
sdk: '>=3.10.0 <4.0.0'
|
||||
>>>>>>> Stashed changes
|
||||
flutter: ">=3.0.0"
|
||||
|
||||
dependencies:
|
||||
@@ -21,6 +28,11 @@ dependencies:
|
||||
path: ../../../core_localization
|
||||
krow_domain:
|
||||
path: ../../../domain
|
||||
<<<<<<< Updated upstream
|
||||
=======
|
||||
krow_core:
|
||||
path: ../../../core
|
||||
>>>>>>> Stashed changes
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
||||
Reference in New Issue
Block a user