feat(wyatt_app_template): use brickgen
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:starting_template/core/dependency_injection/get_it.dart';
|
||||
import 'package:starting_template/core/flavors/flavor.dart';
|
||||
import 'package:starting_template/core/routes/router.dart';
|
||||
import 'package:starting_template/data/repositories/counter_repository_impl.dart';
|
||||
import 'package:starting_template/domain/repositories/counter_repository.dart';
|
||||
import 'package:starting_template/gen/app_localizations.dart';
|
||||
import 'package:starting_template/presentation/features/counter/blocs/counter_bloc/counter_bloc.dart';
|
||||
import 'package:wyatt_bloc_helper/wyatt_bloc_helper.dart';
|
||||
|
||||
class App extends StatelessWidget {
|
||||
const App({super.key});
|
||||
|
||||
Widget _flavorBanner(Widget child) {
|
||||
final flavor = Flavor.get();
|
||||
if (flavor.banner != null && !kReleaseMode) {
|
||||
return Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: Banner(
|
||||
location: BannerLocation.topEnd,
|
||||
message: flavor.banner!,
|
||||
color: flavor.bannerColor,
|
||||
child: child,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => MultiProvider(
|
||||
repositoryProviders: [
|
||||
RepositoryProvider<CounterRepository>(
|
||||
create: (_) => CounterRepositoryImpl(counterDataSource: getIt()),
|
||||
),
|
||||
],
|
||||
blocProviders: [
|
||||
BlocProvider<CounterBloc>(
|
||||
create: (_) => CounterBloc(),
|
||||
),
|
||||
],
|
||||
child: _flavorBanner(
|
||||
MaterialApp.router(
|
||||
title: 'Display Name',
|
||||
debugShowCheckedModeBanner: false,
|
||||
routerDelegate: AppRouter.router.routerDelegate,
|
||||
routeInformationParser: AppRouter.router.routeInformationParser,
|
||||
routeInformationProvider: AppRouter.router.routeInformationProvider,
|
||||
localizationsDelegates: const [
|
||||
AppLocalizations.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
supportedLocales: AppLocalizations.supportedLocales,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
part 'counter_event.dart';
|
||||
part 'counter_state.dart';
|
||||
|
||||
/// {@template counter_bloc}
|
||||
/// CounterBloc description
|
||||
/// {@endtemplate}
|
||||
class CounterBloc extends Bloc<CounterEvent, CounterState> {
|
||||
/// {@macro counter_bloc}
|
||||
CounterBloc() : super(const CounterInitial()) {
|
||||
on<CustomCounterEvent>(_onCustomCounterEvent);
|
||||
}
|
||||
|
||||
FutureOr<void> _onCustomCounterEvent(
|
||||
CustomCounterEvent event,
|
||||
Emitter<CounterState> emit,
|
||||
) async {
|
||||
// TODO(wyatt): Add custom UI logic
|
||||
const _ = 1 + 1;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
part of 'counter_bloc.dart';
|
||||
|
||||
/// {@template counter_event}
|
||||
/// CounterEvent description
|
||||
/// {@endtemplate}
|
||||
abstract class CounterEvent extends Equatable {
|
||||
/// {@macro counter_event}
|
||||
const CounterEvent();
|
||||
}
|
||||
|
||||
/// {@template custom_counter_event}
|
||||
/// Event added when some custom logic happens
|
||||
/// {@endtemplate}
|
||||
class CustomCounterEvent extends CounterEvent {
|
||||
/// {@macro custom_counter_event}
|
||||
const CustomCounterEvent();
|
||||
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
part of 'counter_bloc.dart';
|
||||
|
||||
/// {@template counter_state}
|
||||
/// CounterState description
|
||||
/// {@endtemplate}
|
||||
abstract class CounterState extends Equatable {
|
||||
/// {@macro counter_state}
|
||||
const CounterState();
|
||||
}
|
||||
|
||||
/// {@template counter_initial}
|
||||
/// The initial state of CounterState
|
||||
/// {@endtemplate}
|
||||
class CounterInitial extends CounterState {
|
||||
/// {@macro counter_initial}
|
||||
const CounterInitial();
|
||||
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:starting_template/domain/usecases/counter/decrement.dart';
|
||||
import 'package:starting_template/domain/usecases/counter/get_current.dart';
|
||||
import 'package:starting_template/domain/usecases/counter/increment.dart';
|
||||
import 'package:starting_template/domain/usecases/counter/reset.dart';
|
||||
|
||||
part 'counter_state.dart';
|
||||
|
||||
/// {@template counter_cubit}
|
||||
/// CounterCubit manages UI depending on counter state.
|
||||
/// {@endtemplate}
|
||||
class CounterCubit extends Cubit<CounterState> {
|
||||
/// {@macro counter_cubit}
|
||||
CounterCubit({
|
||||
required Decrement decrement,
|
||||
required Increment increment,
|
||||
required GetCurrent getCurrent,
|
||||
required Reset reset,
|
||||
}) : _decrement = decrement,
|
||||
_increment = increment,
|
||||
_getCurrent = getCurrent,
|
||||
_reset = reset,
|
||||
super(const CounterState(0));
|
||||
|
||||
final Decrement _decrement;
|
||||
final Increment _increment;
|
||||
final GetCurrent _getCurrent;
|
||||
final Reset _reset;
|
||||
|
||||
/// Decrement counter.
|
||||
FutureOr<void> decrement([int by = 1]) async {
|
||||
final result = await _decrement.call(by);
|
||||
|
||||
result.fold(
|
||||
(integer) => emit(CounterState(integer.value)),
|
||||
addError,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/// Increment counter.
|
||||
FutureOr<void> increment([int by = 1]) async {
|
||||
final result = await _increment.call(by);
|
||||
|
||||
result.fold(
|
||||
(integer) => emit(CounterState(integer.value)),
|
||||
addError,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/// Get current counter state.
|
||||
FutureOr<void> getCurrent() async {
|
||||
final result = await _getCurrent.call(null);
|
||||
|
||||
result.fold(
|
||||
(integer) => emit(CounterState(integer.value)),
|
||||
addError,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/// Reset counter state.
|
||||
FutureOr<void> reset() async {
|
||||
final result = await _reset.call(null);
|
||||
|
||||
result.fold(
|
||||
(integer) => emit(CounterState(integer.value)),
|
||||
addError,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@override
|
||||
void onError(Object error, StackTrace stackTrace) {
|
||||
emit(state);
|
||||
super.onError(error, stackTrace);
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
part of 'counter_cubit.dart';
|
||||
|
||||
/// {@template counter_state}
|
||||
/// CounterState containing counter value
|
||||
/// {@endtemplate}
|
||||
class CounterState extends Equatable {
|
||||
/// {@macro counter_state}
|
||||
const CounterState(this.value);
|
||||
|
||||
final int value;
|
||||
|
||||
@override
|
||||
List<Object?> get props => [value];
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:starting_template/presentation/features/counter/screens/counter_provider.dart';
|
||||
|
||||
class Counter extends StatelessWidget {
|
||||
const Counter({super.key});
|
||||
|
||||
static const String pageName = 'counterPage';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => const CounterProvider();
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:starting_template/core/extensions/build_context_extension.dart';
|
||||
import 'package:starting_template/domain/repositories/counter_repository.dart';
|
||||
import 'package:starting_template/domain/usecases/counter/decrement.dart';
|
||||
import 'package:starting_template/domain/usecases/counter/get_current.dart';
|
||||
import 'package:starting_template/domain/usecases/counter/increment.dart';
|
||||
import 'package:starting_template/domain/usecases/counter/reset.dart';
|
||||
import 'package:starting_template/presentation/features/counter/blocs/counter_cubit/counter_cubit.dart';
|
||||
import 'package:starting_template/presentation/features/counter/screens/widgets/counter_consumer_widget.dart';
|
||||
import 'package:starting_template/presentation/shared/layouts/wyatt_app_template_scaffold.dart';
|
||||
import 'package:wyatt_bloc_helper/wyatt_bloc_helper.dart';
|
||||
|
||||
/// {@template counter_provider}
|
||||
/// CounterProvider provides bloc to his children.
|
||||
/// {@endtemplate}
|
||||
class CounterProvider extends CubitProviderScreen<CounterCubit, CounterState> {
|
||||
/// {@macro counter_provider}
|
||||
const CounterProvider({super.key});
|
||||
|
||||
@override
|
||||
CounterCubit create(BuildContext context) => CounterCubit(
|
||||
decrement: Decrement(
|
||||
counterRepository: repo<CounterRepository>(context),
|
||||
),
|
||||
increment: Increment(
|
||||
counterRepository: repo<CounterRepository>(context),
|
||||
),
|
||||
getCurrent: GetCurrent(
|
||||
counterRepository: repo<CounterRepository>(context),
|
||||
),
|
||||
reset: Reset(
|
||||
counterRepository: repo<CounterRepository>(context),
|
||||
),
|
||||
);
|
||||
|
||||
@override
|
||||
CounterCubit init(BuildContext context, CounterCubit bloc) =>
|
||||
bloc..getCurrent();
|
||||
|
||||
@override
|
||||
Widget builder(BuildContext context) => WyattAppTemplateScaffold(
|
||||
title: Text(context.l10n.counterAppBarTitle),
|
||||
body: const CounterConsumerWidget(),
|
||||
fabChildren: [
|
||||
FloatingActionButton(
|
||||
heroTag: 'increment_tag',
|
||||
onPressed: () => bloc(context).increment(),
|
||||
child: const Icon(Icons.add),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
FloatingActionButton(
|
||||
heroTag: 'increment_10_tag',
|
||||
onPressed: () => bloc(context).increment(10),
|
||||
child: const Text('+10'),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
FloatingActionButton(
|
||||
heroTag: 'decrement_tag',
|
||||
onPressed: () => bloc(context).decrement(),
|
||||
child: const Icon(Icons.remove),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
FloatingActionButton(
|
||||
heroTag: 'decrement_10_tag',
|
||||
onPressed: () => bloc(context).decrement(10),
|
||||
child: const Text('-10'),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
FloatingActionButton(
|
||||
heroTag: 'reset_tag',
|
||||
onPressed: () => bloc(context).reset(),
|
||||
child: const Icon(Icons.refresh),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:starting_template/core/extensions/build_context_extension.dart';
|
||||
import 'package:starting_template/presentation/features/counter/blocs/counter_cubit/counter_cubit.dart';
|
||||
import 'package:wyatt_bloc_helper/wyatt_bloc_helper.dart';
|
||||
|
||||
/// {@template counter_consumer_widget}
|
||||
/// CounterConsumerWidget is a stateful widget. Aware of state changes.
|
||||
/// {@endtemplate}
|
||||
class CounterConsumerWidget
|
||||
extends CubitConsumerScreen<CounterCubit, CounterState> {
|
||||
/// {@macro counter_consumer_widget}
|
||||
const CounterConsumerWidget({super.key});
|
||||
|
||||
@override
|
||||
Widget onBuild(BuildContext context, CounterState state) => Text(
|
||||
context.l10n.youHavePushed(state.value),
|
||||
textAlign: TextAlign.center,
|
||||
style: Theme.of(context).textTheme.headline3,
|
||||
);
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// {@template counter_widget}
|
||||
/// CounterWidget is a stateless widget. (Not aware of cubit or bloc states)
|
||||
/// {@endtemplate}
|
||||
class CounterWidget extends StatelessWidget {
|
||||
/// {@macro counter_widget}
|
||||
const CounterWidget({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Container();
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:starting_template/core/extensions/build_context_extension.dart';
|
||||
import 'package:starting_template/gen/assets.gen.dart';
|
||||
import 'package:starting_template/presentation/features/counter/counter.dart';
|
||||
import 'package:starting_template/presentation/shared/layouts/wyatt_app_template_scaffold.dart';
|
||||
|
||||
class Home extends StatelessWidget {
|
||||
const Home({super.key});
|
||||
|
||||
static const String pageName = 'homePage';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => WyattAppTemplateScaffold(
|
||||
body: Center(
|
||||
child: Column(
|
||||
children: [
|
||||
Assets.images.wyattLogo.image(width: 150),
|
||||
const Gap(30),
|
||||
ElevatedButton(
|
||||
child: Text(context.l10n.goToCounter),
|
||||
onPressed: () => context.pushNamed(Counter.pageName),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class WyattAppTemplateScaffold extends StatelessWidget {
|
||||
const WyattAppTemplateScaffold({
|
||||
required this.body,
|
||||
super.key,
|
||||
this.title,
|
||||
this.fabChildren,
|
||||
});
|
||||
|
||||
final Widget? title;
|
||||
final Widget body;
|
||||
final List<Widget>? fabChildren;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Scaffold(
|
||||
appBar: AppBar(title: title),
|
||||
body: body,
|
||||
floatingActionButton: (fabChildren?.isNotEmpty ?? false)
|
||||
? Column(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: fabChildren!,
|
||||
)
|
||||
: null,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
# just to keep empty folder in brick generation
|
||||
Reference in New Issue
Block a user