# Catatan Seekor Flutter

Flutter adalah framework open-source dari Google untuk membangun aplikasi mobile, web, dan desktop dengan satu codebase menggunakan bahasa Dart.

## Fundamental

### Widget Structure

```dart
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}
```

### Stateless vs Stateful Widgets

```dart
// Stateless Widget
class MyStatelessWidget extends StatelessWidget {
  final String title;
  
  const MyStatelessWidget({Key? key, required this.title}) : super(key: key);
  
  @override
  Widget build(BuildContext context) {
    return Text(title);
  }
}

// Stateful Widget
class MyStatefulWidget extends StatefulWidget {
  @override
  _MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}

class _MyStatefulWidgetState extends State<MyStatefulWidget> {
  int _counter = 0;
  
  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }
  
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text('$_counter'),
        ElevatedButton(
          onPressed: _incrementCounter,
          child: Text('Increment'),
        ),
      ],
    );
  }
}
```

### Common Widgets

```dart
// Layout Widgets
Container(
  padding: EdgeInsets.all(16.0),
  margin: EdgeInsets.all(8.0),
  child: Column(
    children: [
      Text('Hello Flutter'),
      SizedBox(height: 16.0),
      ElevatedButton(
        onPressed: () {},
        child: Text('Click Me'),
      ),
    ],
  ),
)

// List Widgets
ListView.builder(
  itemCount: items.length,
  itemBuilder: (context, index) {
    return ListTile(
      title: Text(items[index]),
      onTap: () => print('Tapped $index'),
    );
  },
)
```

## State Management

### Provider Pattern

```dart
class CounterProvider extends ChangeNotifier {
  int _count = 0;
  
  int get count => _count;
  
  void increment() {
    _count++;
    notifyListeners();
  }
}

// Usage
ChangeNotifierProvider(
  create: (context) => CounterProvider(),
  child: Consumer<CounterProvider>(
    builder: (context, counter, child) {
      return Text('${counter.count}');
    },
  ),
)
```

### Bloc Pattern

```dart
abstract class CounterEvent {}
class Increment extends CounterEvent {}
class Decrement extends CounterEvent {}

class CounterBloc extends Bloc<CounterEvent, int> {
  CounterBloc() : super(0);
  
  @override
  Stream<int> mapEventToState(CounterEvent event) async* {
    if (event is Increment) {
      yield state + 1;
    } else if (event is Decrement) {
      yield state - 1;
    }
  }
}
```

## Build Flavors

Build flavors memungkinkan aplikasi Flutter memiliki konfigurasi berbeda untuk development, staging, dan production.

### Flavor Configuration

```dart
// lib/flavor_config.dart
enum Flavor {
  development,
  staging,
  production,
}

class FlavorConfig {
  final Flavor flavor;
  final String apiBaseUrl;
  final String appName;
  
  static FlavorConfig? _instance;
  
  factory FlavorConfig({
    required Flavor flavor,
    required String apiBaseUrl,
    required String appName,
  }) {
    _instance ??= FlavorConfig._internal(
      flavor: flavor,
      apiBaseUrl: apiBaseUrl,
      appName: appName,
    );
    return _instance!;
  }
  
  FlavorConfig._internal({
    required this.flavor,
    required this.apiBaseUrl,
    required this.appName,
  });
  
  static FlavorConfig get instance {
    return _instance!;
  }
  
  static bool isDevelopment() => _instance?.flavor == Flavor.development;
  static bool isStaging() => _instance?.flavor == Flavor.staging;
  static bool isProduction() => _instance?.flavor == Flavor.production;
}
```

### Main Files for Different Flavors

```dart
// lib/main_development.dart
void main() {
  FlavorConfig(
    flavor: Flavor.development,
    apiBaseUrl: 'https://dev-api.example.com',
    appName: 'Flutter Dev',
  );
  runApp(MyApp());
}

// lib/main_staging.dart
void main() {
  FlavorConfig(
    flavor: Flavor.staging,
    apiBaseUrl: 'https://staging-api.example.com',
    appName: 'Flutter Staging',
  );
  runApp(MyApp());
}

// lib/main_production.dart
void main() {
  FlavorConfig(
    flavor: Flavor.production,
    apiBaseUrl: 'https://api.example.com',
    appName: 'Flutter App',
  );
  runApp(MyApp());
}
```

## References

### Build Flavors

* [Create Build Flavor in Flutter Application (iOS & Android)](https://dwirandyh.medium.com/create-build-flavor-in-flutter-application-ios-android-fb35a81a9fac)
* [Flutter Flavors: serving your apps in multiple tastes](https://applover.com/blog/flutter-flavors-serving-your-apps-in-multiple-tastes/)
* [Flutter Flavors Setup with multiple Firebase Environments using FlutterFire and Very Good CLI](https://codewithandrea.com/articles/flutter-flavors-for-firebase-apps/)

## Tools

### Development Tools

* Flutter CLI
* Dart DevTools
* VS Code / Android Studio
* Flutter Inspector

### Testing

* Flutter Test
* Integration Test
* Widget Test
* Golden Test

### Build & Deploy

* Flutter Build
* Flutter Run
* Flutter Install
* Flutter Clean
