feat: Implement Flutter flavors for dev, stage, and prod environments with corresponding configurations and build scripts.
This commit is contained in:
13
mobile-apps/apps/krow_staff/lib/app_config.dart
Normal file
13
mobile-apps/apps/krow_staff/lib/app_config.dart
Normal file
@@ -0,0 +1,13 @@
|
||||
enum Environment { dev, stage, prod }
|
||||
|
||||
class AppConfig {
|
||||
final Environment environment;
|
||||
final String appTitle;
|
||||
final String apiBaseUrl;
|
||||
|
||||
AppConfig({
|
||||
required this.environment,
|
||||
required this.appTitle,
|
||||
required this.apiBaseUrl,
|
||||
});
|
||||
}
|
||||
@@ -1,122 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'main_prod.dart' as prod;
|
||||
|
||||
void main() {
|
||||
runApp(const MyApp());
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
const MyApp({super.key});
|
||||
|
||||
// This widget is the root of your application.
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
title: 'Flutter Demo',
|
||||
theme: ThemeData(
|
||||
// This is the theme of your application.
|
||||
//
|
||||
// TRY THIS: Try running your application with "flutter run". You'll see
|
||||
// the application has a purple toolbar. Then, without quitting the app,
|
||||
// try changing the seedColor in the colorScheme below to Colors.green
|
||||
// and then invoke "hot reload" (save your changes or press the "hot
|
||||
// reload" button in a Flutter-supported IDE, or press "r" if you used
|
||||
// the command line to start the app).
|
||||
//
|
||||
// Notice that the counter didn't reset back to zero; the application
|
||||
// state is not lost during the reload. To reset the state, use hot
|
||||
// restart instead.
|
||||
//
|
||||
// This works for code too, not just values: Most code changes can be
|
||||
// tested with just a hot reload.
|
||||
colorScheme: .fromSeed(seedColor: Colors.deepPurple),
|
||||
),
|
||||
home: const MyHomePage(title: 'Flutter Demo Home Page'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MyHomePage extends StatefulWidget {
|
||||
const MyHomePage({super.key, required this.title});
|
||||
|
||||
// This widget is the home page of your application. It is stateful, meaning
|
||||
// that it has a State object (defined below) that contains fields that affect
|
||||
// how it looks.
|
||||
|
||||
// This class is the configuration for the state. It holds the values (in this
|
||||
// case the title) provided by the parent (in this case the App widget) and
|
||||
// used by the build method of the State. Fields in a Widget subclass are
|
||||
// always marked "final".
|
||||
|
||||
final String title;
|
||||
|
||||
@override
|
||||
State<MyHomePage> createState() => _MyHomePageState();
|
||||
}
|
||||
|
||||
class _MyHomePageState extends State<MyHomePage> {
|
||||
int _counter = 0;
|
||||
|
||||
void _incrementCounter() {
|
||||
setState(() {
|
||||
// This call to setState tells the Flutter framework that something has
|
||||
// changed in this State, which causes it to rerun the build method below
|
||||
// so that the display can reflect the updated values. If we changed
|
||||
// _counter without calling setState(), then the build method would not be
|
||||
// called again, and so nothing would appear to happen.
|
||||
_counter++;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// This method is rerun every time setState is called, for instance as done
|
||||
// by the _incrementCounter method above.
|
||||
//
|
||||
// The Flutter framework has been optimized to make rerunning build methods
|
||||
// fast, so that you can just rebuild anything that needs updating rather
|
||||
// than having to individually change instances of widgets.
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
// TRY THIS: Try changing the color here to a specific color (to
|
||||
// Colors.amber, perhaps?) and trigger a hot reload to see the AppBar
|
||||
// change color while the other colors stay the same.
|
||||
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
|
||||
// Here we take the value from the MyHomePage object that was created by
|
||||
// the App.build method, and use it to set our appbar title.
|
||||
title: Text(widget.title),
|
||||
),
|
||||
body: Center(
|
||||
// Center is a layout widget. It takes a single child and positions it
|
||||
// in the middle of the parent.
|
||||
child: Column(
|
||||
// Column is also a layout widget. It takes a list of children and
|
||||
// arranges them vertically. By default, it sizes itself to fit its
|
||||
// children horizontally, and tries to be as tall as its parent.
|
||||
//
|
||||
// Column has various properties to control how it sizes itself and
|
||||
// how it positions its children. Here we use mainAxisAlignment to
|
||||
// center the children vertically; the main axis here is the vertical
|
||||
// axis because Columns are vertical (the cross axis would be
|
||||
// horizontal).
|
||||
//
|
||||
// TRY THIS: Invoke "debug painting" (choose the "Toggle Debug Paint"
|
||||
// action in the IDE, or press "p" in the console), to see the
|
||||
// wireframe for each widget.
|
||||
mainAxisAlignment: .center,
|
||||
children: [
|
||||
const Text('You have pushed the button this many times:'),
|
||||
Text(
|
||||
'$_counter',
|
||||
style: Theme.of(context).textTheme.headlineMedium,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: _incrementCounter,
|
||||
tooltip: 'Increment',
|
||||
child: const Icon(Icons.add),
|
||||
),
|
||||
);
|
||||
}
|
||||
prod.main();
|
||||
}
|
||||
|
||||
13
mobile-apps/apps/krow_staff/lib/main_dev.dart
Normal file
13
mobile-apps/apps/krow_staff/lib/main_dev.dart
Normal file
@@ -0,0 +1,13 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'app_config.dart';
|
||||
import 'my_app.dart';
|
||||
|
||||
void main() {
|
||||
var configuredApp = AppConfig(
|
||||
environment: Environment.dev,
|
||||
appTitle: 'Krow Staff (Dev)',
|
||||
apiBaseUrl: 'https://dev-api.krow.com',
|
||||
);
|
||||
|
||||
runApp(MyApp(config: configuredApp));
|
||||
}
|
||||
13
mobile-apps/apps/krow_staff/lib/main_prod.dart
Normal file
13
mobile-apps/apps/krow_staff/lib/main_prod.dart
Normal file
@@ -0,0 +1,13 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'app_config.dart';
|
||||
import 'my_app.dart';
|
||||
|
||||
void main() {
|
||||
var configuredApp = AppConfig(
|
||||
environment: Environment.prod,
|
||||
appTitle: 'Krow Staff',
|
||||
apiBaseUrl: 'https://api.krow.com',
|
||||
);
|
||||
|
||||
runApp(MyApp(config: configuredApp));
|
||||
}
|
||||
13
mobile-apps/apps/krow_staff/lib/main_stage.dart
Normal file
13
mobile-apps/apps/krow_staff/lib/main_stage.dart
Normal file
@@ -0,0 +1,13 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'app_config.dart';
|
||||
import 'my_app.dart';
|
||||
|
||||
void main() {
|
||||
var configuredApp = AppConfig(
|
||||
environment: Environment.stage,
|
||||
appTitle: 'Krow Staff (Stage)',
|
||||
apiBaseUrl: 'https://stage-api.krow.com',
|
||||
);
|
||||
|
||||
runApp(MyApp(config: configuredApp));
|
||||
}
|
||||
122
mobile-apps/apps/krow_staff/lib/my_app.dart
Normal file
122
mobile-apps/apps/krow_staff/lib/my_app.dart
Normal file
@@ -0,0 +1,122 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'app_config.dart';
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
final AppConfig config;
|
||||
|
||||
const MyApp({super.key, required this.config});
|
||||
|
||||
// This widget is the root of your application.
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
title: config.appTitle,
|
||||
theme: ThemeData(
|
||||
// This is the theme of your application.
|
||||
//
|
||||
// TRY THIS: Try running your application with "flutter run". You'll see
|
||||
// the application has a purple toolbar. Then, without quitting the app,
|
||||
// try changing the seedColor in the colorScheme below to Colors.green
|
||||
// and then invoke "hot reload" (save your changes or press the "hot
|
||||
// reload" button in a Flutter-supported IDE, or press "r" if you used
|
||||
// the command line to start the app).
|
||||
//
|
||||
// Notice that the counter didn't reset back to zero; the application
|
||||
// state is not lost during the reload. To reset the state, use hot
|
||||
// restart instead.
|
||||
//
|
||||
// This works for code too, not just values: Most code changes can be
|
||||
// tested with just a hot reload.
|
||||
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
|
||||
useMaterial3: true,
|
||||
),
|
||||
home: MyHomePage(title: '${config.appTitle} Home Page'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MyHomePage extends StatefulWidget {
|
||||
const MyHomePage({super.key, required this.title});
|
||||
|
||||
// This widget is the home page of your application. It is stateful, meaning
|
||||
// that it has a State object (defined below) that contains fields that affect
|
||||
// how it looks.
|
||||
|
||||
// This class is the configuration for the state. It holds the values (in this
|
||||
// case the title) provided by the parent (in this case the App widget) and
|
||||
// used by the build method of the State. Fields in a Widget subclass are
|
||||
// always marked "final".
|
||||
|
||||
final String title;
|
||||
|
||||
@override
|
||||
State<MyHomePage> createState() => _MyHomePageState();
|
||||
}
|
||||
|
||||
class _MyHomePageState extends State<MyHomePage> {
|
||||
int _counter = 0;
|
||||
|
||||
void _incrementCounter() {
|
||||
setState(() {
|
||||
// This call to setState tells the Flutter framework that something has
|
||||
// changed in this State, which causes it to rerun the build method below
|
||||
// so that the display can reflect the updated values. If we changed
|
||||
// _counter without calling setState(), then the build method would not be
|
||||
// called again, and so nothing would appear to happen.
|
||||
_counter++;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// This method is rerun every time setState is called, for instance as done
|
||||
// by the _incrementCounter method above.
|
||||
//
|
||||
// The Flutter framework has been optimized to make rerunning build methods
|
||||
// fast, so that you can just rebuild anything that needs updating rather
|
||||
// than having to individually change instances of widgets.
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
// TRY THIS: Try changing the color here to a specific color (to
|
||||
// Colors.amber, perhaps?) and trigger a hot reload to see the AppBar
|
||||
// change color while the other colors stay the same.
|
||||
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
|
||||
// Here we take the value from the MyHomePage object that was created by
|
||||
// the App.build method, and use it to set our appbar title.
|
||||
title: Text(widget.title),
|
||||
),
|
||||
body: Center(
|
||||
// Center is a layout widget. It takes a single child and positions it
|
||||
// in the middle of the parent.
|
||||
child: Column(
|
||||
// Column is also a layout widget. It takes a list of children and
|
||||
// arranges them vertically. By default, it sizes itself to fit its
|
||||
// children horizontally, and tries to be as tall as its parent.
|
||||
//
|
||||
// Column has various properties to control how it sizes itself and
|
||||
// how it positions its children. Here we use mainAxisAlignment to
|
||||
// center the children vertically; the main axis here is the vertical
|
||||
// axis because Columns are vertical (the cross axis would be
|
||||
// horizontal).
|
||||
//
|
||||
// TRY THIS: Invoke "debug painting" (choose the "Toggle Debug Paint"
|
||||
// action in the IDE, or press "p" in the console), to see the
|
||||
// wireframe for each widget.
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
const Text('You have pushed the button this many times:'),
|
||||
Text(
|
||||
'$_counter',
|
||||
style: Theme.of(context).textTheme.headlineMedium,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: _incrementCounter,
|
||||
tooltip: 'Increment',
|
||||
child: const Icon(Icons.add),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -7,13 +7,21 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'package:krow_staff/main.dart';
|
||||
import 'package:krow_staff/app_config.dart';
|
||||
import 'package:krow_staff/my_app.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
|
||||
// Build our app and trigger a frame.
|
||||
await tester.pumpWidget(const MyApp());
|
||||
await tester.pumpWidget(
|
||||
MyApp(
|
||||
config: AppConfig(
|
||||
environment: Environment.dev,
|
||||
appTitle: 'Test App',
|
||||
apiBaseUrl: 'https://test.com',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// Verify that our counter starts at 0.
|
||||
expect(find.text('0'), findsOneWidget);
|
||||
|
||||
@@ -9,3 +9,39 @@ workspace:
|
||||
|
||||
dev_dependencies:
|
||||
melos: ^7.3.0
|
||||
|
||||
melos:
|
||||
command:
|
||||
bootstrap:
|
||||
usePubspecOverrides: true
|
||||
scripts:
|
||||
run:staff:dev:
|
||||
exec: flutter run --flavor dev -t lib/main_dev.dart
|
||||
packageFilters:
|
||||
scope: krow_staff
|
||||
description: Run krow_staff app in dev flavor
|
||||
run:staff:stage:
|
||||
exec: flutter run --flavor stage -t lib/main_stage.dart
|
||||
packageFilters:
|
||||
scope: krow_staff
|
||||
description: Run krow_staff app in stage flavor
|
||||
run:staff:prod:
|
||||
exec: flutter run --flavor prod -t lib/main_prod.dart
|
||||
packageFilters:
|
||||
scope: krow_staff
|
||||
description: Run krow_staff app in prod flavor
|
||||
build:staff:dev:
|
||||
exec: flutter build apk --flavor dev -t lib/main_dev.dart
|
||||
packageFilters:
|
||||
scope: krow_staff
|
||||
description: Build krow_staff apk in dev flavor
|
||||
build:staff:stage:
|
||||
exec: flutter build apk --flavor stage -t lib/main_stage.dart
|
||||
packageFilters:
|
||||
scope: krow_staff
|
||||
description: Build krow_staff apk in stage flavor
|
||||
build:staff:prod:
|
||||
exec: flutter build apk --flavor prod -t lib/main_prod.dart
|
||||
packageFilters:
|
||||
scope: krow_staff
|
||||
description: Build krow_staff apk in prod flavor
|
||||
|
||||
Reference in New Issue
Block a user