flutter_base_architecture_plugin 0.0.2-dev.5 copy "flutter_base_architecture_plugin: ^0.0.2-dev.5" to clipboard
flutter_base_architecture_plugin: ^0.0.2-dev.5 copied to clipboard

unlisted

A robust and scalable Flutter plugin that provides a solid foundation for building production-ready apps. Includes API calls, BLoC state management, navigation, dependency injection, and localization [...]

Flutter Base Architecture Plugin #

A robust and scalable Flutter plugin that provides a solid foundation for building production-ready apps. Includes API calls, BLoC state management, navigation, dependency injection, and localization out of the box. Perfect for developers looking to save time and follow best practices in Flutter app development.

🚀 Features #

  • BLoC State Management: Built-in base classes for BLoC pattern implementation
  • API Integration: Pre-configured REST API client with Dio
  • Dependency Injection: Singleton-based DI system for plugin services
  • Localization: Multi-language support with easy localization management
  • Navigation: Enhanced navigation extensions with authentication checks
  • Error Handling: Comprehensive error handling and network monitoring
  • Logging: Configurable logging with interceptors
  • Network Info: Real-time connectivity status monitoring
  • Base Components: Reusable base classes for screens, states, and controllers

📦 Installation #

Add this to your package's pubspec.yaml file:

dependencies:
  flutter_base_architecture_plugin:
    path: ../flutter_base_architecture_plugin # For local development
    # git: https://github.com/your-repo/flutter_base_architecture_plugin.git # For git dependency

For dependency injection in your app, also add:

dependencies:
  get_it: ^7.6.0
  injectable: ^2.3.2

dev_dependencies:
  injectable_generator: ^2.4.1
  build_runner: ^2.4.7

🛠️ Setup #

1. Initialize the Plugin #

In your main.dart:

import 'package:flutter/material.dart';
import 'package:flutter_base_architecture_plugin/core/base_state.dart';
import 'your_injector.dart'; // Your app's injector

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  // Setup dependency injection
  await Injector.setup();

  runApp(const MyApp());
}

2. Create Your App's Injector #

Create lib/inject/injector.dart:

import 'package:flutter_base_architecture_plugin/inject/base_injector.dart';
import 'package:flutter_base_architecture_plugin/base_arch_controller/base_arch_controller.dart';
import 'package:flutter_base_architecture_plugin/imports/core_imports.dart';
import 'package:flutter_base_architecture_plugin/services/app_routes/app_routes_service.dart';
import 'package:flutter_base_architecture_plugin/services/localization/localization_service.dart';
import 'package:flutter_base_architecture_plugin/core/network/network_info.dart';
import 'package:get_it/get_it.dart';
import 'package:injectable/injectable.dart';

import '../api/home/home_api/home_api.dart';
import '../service/home/home_service.dart';
import 'injector.config.dart';

final getIt = GetIt.instance;

@InjectableInit()
void configureDependencies() => getIt.init();

// Module to register plugin and app-specific dependencies
@module
abstract class PluginModule {
  @singleton
  HomeApi get homeApi => HomeApi(BaseInjector.restApiClient);

  @singleton
  HomeService get homeService => HomeService(getIt<HomeApi>());

  @singleton
  LocalizationService get localizationService =>
      BaseInjector.localizationService;

  @singleton
  AppRoutesService get appRoutesService => BaseInjector.appRoutesService;

  @singleton
  BaseArchController get baseArchController =>
      BaseInjector.baseArchController;

  @singleton
  EventBus get eventBus => BaseInjector.eventBus;

  @singleton
  NetworkInfoImpl get networkInfoImpl =>
      BaseInjector.networkInfoImpl;
}

class Injector {
  static Future<bool> setup() async {
    // Configure GetIt dependencies
    configureDependencies();

    // Set external resolver for BaseState
    BaseState.setExternalResolver(Injector.resolve);
    return true;
  }

  static T resolve<T extends Object>() => getIt<T>();
}

3. Generate Dependency Injection Code #

Run the code generator:

dart run build_runner build

4. Configure Your App #

class MyApp extends StatefulWidget {
  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends BaseState<YourMainBloc, MyApp> {
  @override
  void initState() {
    super.initState();
    
    // Configure the base architecture
    bloc.add(SetRestApiConfiguration(
      baseUrl: 'https://your-api.com/api/',
      connectTimeout: 30,
      receiveTimeout: 30,
    ));
    
    bloc.add(SetLocalizationEvent(
      localizationList: [
        EnglishLocalization(),
        // Add more localizations
      ],
    ));
    
    bloc.add(SetProtectedRoutesEvent(
      isAuthenticated: false, // Set based on your auth state
      protectedRoutesList: [
        '/profile',
        '/settings',
        // Add protected routes
      ],
    ));
  }

  @override
  Widget build(BuildContext context) {
    return BlocProvider<YourMainBloc>(
      create: (context) => bloc,
      child: BlocBuilder<YourMainBloc, YourMainData>(
        builder: (context, state) {
          return MaterialApp(
            title: 'Your App',
            home: YourHomeScreen(),
            // Configure other MaterialApp properties
          );
        },
      ),
    );
  }
}

📱 Usage Examples #

Creating a BLoC #

import 'package:injectable/injectable.dart';
import 'package:flutter_base_architecture_plugin/imports/core_imports.dart';

@injectable
class HomeBloc extends BaseBloc<HomeEvent, HomeData> {
  HomeBloc(this._yourService, this._localizationService) : super(initState) {
    on<LoadDataEvent>(_loadData);
  }

  final YourService _yourService;
  final LocalizationService _localizationService;

  static HomeData get initState => HomeDataBuilder()
    ..state = ScreenState.loading
    ..build();

  Future<void> _loadData(LoadDataEvent event, Emitter<HomeData> emit) async {
    try {
      emit(state.rebuild((b) => b..state = ScreenState.loading));
      
      final data = await _yourService.fetchData();
      
      emit(state.rebuild((b) => b
        ..state = ScreenState.content
        ..data = data));
        
    } catch (error) {
      emit(state.rebuild((b) => b
        ..state = ScreenState.error
        ..errorMessage = error.toString()));
    }
  }
}

Creating a Screen #

class HomeScreen extends StatefulWidget {
  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends BaseState<HomeBloc, HomeScreen> {
  @override
  void initState() {
    super.initState();
    bloc.add(LoadDataEvent());
  }

  @override
  Widget build(BuildContext context) {
    return BlocProvider<HomeBloc>(
      create: (context) => bloc,
      child: BlocBuilder<HomeBloc, HomeData>(
        builder: (context, state) {
          switch (state.state) {
            case ScreenState.loading:
              return const Center(child: CircularProgressIndicator());
              
            case ScreenState.content:
              return _buildContent(state);
              
            case ScreenState.error:
              return _buildError(state);
              
            default:
              return Container();
          }
        },
      ),
    );
  }

  Widget _buildContent(HomeData state) {
    return Scaffold(
      appBar: AppBar(title: Text('Home')),
      body: Column(
        children: [
          // Your content here
          ElevatedButton(
            onPressed: () => context.pushNamed('/details'),
            child: Text('Navigate to Details'),
          ),
        ],
      ),
    );
  }

  Widget _buildError(HomeData state) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('Error: ${state.errorMessage}'),
            ElevatedButton(
              onPressed: () => bloc.add(LoadDataEvent()),
              child: Text('Retry'),
            ),
          ],
        ),
      ),
    );
  }
}

API Integration #

@injectable
class YourApi {
  YourApi(this._restApiClient);
  
  final RestApiClient _restApiClient;

  Future<List<YourModel>> fetchData() async {
    final response = await _restApiClient.request(
      path: '/data',
      requestMethod: RequestMethod.GET,
      data: RequestData(),
    );
    
    if (response.data != null) {
      return (response.data!['results'] as List)
          .map((json) => YourModel.fromJson(json))
          .toList();
    }
    
    throw Exception('Failed to fetch data');
  }
}
// Navigate with automatic auth check
context.pushNamedWithAuthCheck('/protected-route');

// Regular navigation
context.pushNamed('/public-route');

// Navigation with parameters
context.pushNamed('/details', arguments: {'id': 123});

Localization #

// Create your localization class
class AppEnglishLocalization extends BaseLocalization {
  @override
  String get appName => 'My App';
  
  @override
  String get welcome => 'Welcome';
  
  // Add more translations
}

// Use in widgets
Text(LocalizationService.currentLocalization().welcome)

🏗️ Architecture Overview #

├── Core Components
│   ├── BaseBloc - Base class for all BLoCs
│   ├── BaseState - Base class for all StatefulWidgets
│   ├── BaseArchController - Main app controller
│   └── Event Bus - App-wide event communication
│
├── Network Layer
│   ├── RestApiClient - HTTP client wrapper
│   ├── NetworkInfo - Connectivity monitoring
│   └── Error Handling - Centralized error management
│
├── Dependency Injection
│   ├── BaseInjector - Plugin's DI system (Singleton-based)
│   └── External Injector - App's DI system (GetIt Injectable)
│
├── Services
│   ├── LocalizationService - Multi-language support
│   ├── AppRoutesService - Route management
│   └── Custom Services - Your app-specific services
│
└── Extensions
    ├── Navigation Extensions - Enhanced navigation
    ├── Context Extensions - Utility extensions
    └── String Extensions - String utilities

🔧 Configuration #

REST API Configuration #

bloc.add(SetRestApiConfiguration(
  baseUrl: 'https://api.example.com/',
  connectTimeout: 30,
  receiveTimeout: 30,
  defaultHeaders: {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
  },
));

Protected Routes #

bloc.add(SetProtectedRoutesEvent(
  isAuthenticated: userIsLoggedIn,
  protectedRoutesList: [
    '/profile',
    '/settings',
    '/admin',
  ],
));

🚧 Migration from Kiwi to GetIt Injectable #

If you're migrating from an older version that used Kiwi, follow these steps:

  1. Remove Kiwi dependencies from your app's pubspec.yaml
  2. Add GetIt dependencies as shown in installation
  3. Update your injector to use the new pattern shown above
  4. Run code generation with dart run build_runner build
  5. Update BaseState initialization in your main.dart

The plugin now uses a singleton-based approach internally while supporting modern GetIt injectable for app-level dependencies.

📚 Additional Resources #

📄 License #

This project is licensed under the MIT License - see the LICENSE file for details.

0
likes
0
points
433
downloads

Publisher

unverified uploader

Weekly Downloads

A robust and scalable Flutter plugin that provides a solid foundation for building production-ready apps. Includes API calls, BLoC state management, navigation, dependency injection, and localization out of the box. Perfect for developers looking to save time and follow best practices in Flutter app development.

License

unknown (license)

Dependencies

built_value, collection, connectivity_plus, dio, flutter, flutter_bloc, flutter_web_plugins, logger, plugin_platform_interface, rxdart, sprintf, web

More

Packages that depend on flutter_base_architecture_plugin

Packages that implement flutter_base_architecture_plugin