Giter Club home page Giter Club logo

flutter_boilerplate's Introduction

GitHub: zeref278

Buy Me A Coffee

Flutter Boilerplate Project

A boilerplate project created in flutter using Bloc, Retrofit. Depend on code generation.

Features

  • State management and examples
  • Api integration and examples
  • Local database and examples
  • Code generation
  • Local storage
  • Logging
  • Routing
  • Dependency Injection
  • Crashlytics template
  • DarkTheme
  • Multi languages
  • Unit tests
  • Integration test
  • Clean architecture
  • Flutter CI

Some packages:

Getting Started

The Boilerplate contains the minimal implementation required to create a new library or project. The repository code is preloaded with some basic components like basic app architecture, app theme, constants and required dependencies to create a new project. By using boiler plate code as standard initializer, we can have same patterns in all the projects that will inherit it. This will also help in reducing setup & development time by allowing you to use same code pattern and avoid re-writing from scratch.

Up-Coming Features:

  • Handle multi bloc event in the same time by bloc concurrency example
  • Load more infinite list using bloc example
  • Authentication template

Architecture

How to Use

Step 1:

Fork, download or clone this repo by using the link below:

https://github.com/zeref278/flutter_boilerplate.git

Step 2: Go to project root and execute the following command in terminal to get the required dependencies and generate languages, freezed, flutter gen:

flutter pub get
flutter pub run intl_utils:generate
flutter pub run build_runner build --delete-conflicting-outputs

Step 3: Go to /packages/rest_client and execute the following command in terminal to generate model and api client:

flutter pub get && flutter pub run build_runner build --delete-conflicting-outputs

Whenever change freezed file, assets, api

Run command

flutter pub get && flutter pub run build_runner build --delete-conflicting-outputs

Folder structure

flutter_boilerplate/
|- assets/                    (assets)
|- lib/
  |- configs/                 (flavor config)
  |- core/                    (bloc observer, theme,...)
  |- data/                    (repository)
  |- features/                (features page)
  |- generated/               (code generation includes localization and assets generation)
  |- injector/                (dependencies injector)
  |- l10n/                    (localization resources
  |- router/                  (routing)
  |- services/                (app services)
  |- utils/                   (app utils)
|- packages/
  |- rest_client/             (api client)
  |- local_database/          (local database)
|- integration_test
|- test/
  |- dependencies/                (mock dependencies)
  |- features/                (bloc test features)

Create a immutable Model with any features available

  • Define a constructor + the properties
  • Override toString, operator ==, hashCode
  • Implement a copyWith method to clone the object
  • Handling de/serialization

Example

part 'dog_image.freezed.dart';
part 'dog_image.g.dart';

@Freezed(fromJson: true)
class DogImage with _$DogImage {
  const factory DogImage({
    required String message,
    required String status,
  }) = _DogImage;

  factory DogImage.fromJson(Map<String, dynamic> json) =>
      _$DogImageFromJson(json);
}

Implement

final DogImage dogImage = DogImage.fromJson(json);
///
final DogImage dogImage = dogImage.copyWith(status: 'failed');
/// Deep copy, equal operator ...
...

Retrofit:

Create a api client by code generation, you do not need to implement each request manually

Example

part 'dog_api.g.dart';

@RestApi()
abstract class DogApiClient {
  factory DogApiClient(Dio dio, {String baseUrl}) = _DogApiClient;

  @GET('/breeds/image/random')
  Future<DogImage> getDogImageRandom();
}

Generate to

  ///
  @override
  Future<DogImage> getDogImageRandom() async {
    const _extra = <String, dynamic>{};
    final queryParameters = <String, dynamic>{};
    final _headers = <String, dynamic>{};
    final _data = <String, dynamic>{};
    final _result =
        await _dio.fetch<Map<String, dynamic>>(_setStreamType<DogImage>(Options(
      method: 'GET',
      headers: _headers,
      extra: _extra,
    )
            .compose(
              _dio.options,
              '/breeds/image/random',
              queryParameters: queryParameters,
              data: _data,
            )
            .copyWith(baseUrl: baseUrl ?? _dio.options.baseUrl)));
    final value = DogImage.fromJson(_result.data!);
    return value;
  }

And this api client will use the baseUrl from a Dio injector

injector.registerLazySingleton<Dio>(
  () {
  /// TODO: custom DIO here
    final Dio dio = Dio(
      BaseOptions(
        baseUrl: AppConfig.baseUrl,
      ),
    );
    if (!kReleaseMode) {
      dio.interceptors.add(
        LogInterceptor(
          requestHeader: true,
          requestBody: true,
          responseHeader: true,
          responseBody: true,
          request: false,
        ),
      );
    }
    return dio;
  },
  instanceName: dioInstance,
);

injector.registerFactory<DogApiClient>(
  () => DogApiClient(
    injector(instanceName: dioInstance),
  ),
);

Mockito and Bloc tests:

If a bloc that you want to test have a required dependencies, you must add it into annotations @GenerateMocks in /test/app_test/app_test.dart:

@GenerateMocks([
  DogImageRandomRepository,
  LogService,

  /// TODO
])
void main() {}

Run the following command to generate a mock dependency

flutter pub run build_runner build --delete-conflicting-outputs

Write a test file:

setUp(() {
    bloc = DogImageRandomBloc(
      dogImageRandomRepository: repository,
      logService: logService,
    );
  });

  group('test add event [DogImageRandomRandomRequested]', () {
    blocTest(
      'emit state when success',
      setUp: () {
        when(repository.getDogImageRandom())
            .thenAnswer((_) => Future<DogImage>.value(image));
      },
      build: () => bloc,
      act: (_) => bloc.add(
        const DogImageRandomRandomRequested(),
      ),
      expect: () => [
        isA<DogImageRandomState>().having(
          (state) => state.status,
          'status',
          UIStatus.loading,
        ),
        isA<DogImageRandomState>()
            .having(
              (state) => state.status,
              'status',
              UIStatus.loadSuccess,
            )
            .having(
              (state) => state.dogImage,
              'image',
              image,
            ),
      ],
    );

    blocTest(
      'emit state when failed',
      setUp: () {
        when(repository.getDogImageRandom()).thenThrow(Exception('error'));
      },
      build: () => bloc,
      seed: () => const DogImageRandomState(dogImage: image),
      act: (_) => bloc.add(
        const DogImageRandomRandomRequested(),
      ),
      expect: () => [
        isA<DogImageRandomState>().having(
          (state) => state.status,
          'status',
          UIStatus.loading,
        ),
        isA<DogImageRandomState>()
            .having(
              (state) => state.status,
              'status',
              UIStatus.actionFailed,
            )
            .having(
              (state) => state.dogImage,
              'image',
              image,
            ),
      ],
    );
  });

If you want to understand architecture or any packages used in this project, you can create a discussion on github repo.

And feel free to create a pull request !

flutter_boilerplate's People

Contributors

tnduydev avatar zeref278 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

flutter_boilerplate's Issues

First load on Chrome - Uncaught (in promise) Error

Hey!
Just giving this a test drive, and after the loading bars all I get is a white screen. From looking through the code (and I'm still fairly new) it should show the MyApp page.

I followed the instructions given, ran a flutter doctor and the generation code a few times and same results. No errors are obvious in the code.

Error:
errors.dart:266 Uncaught (in promise) Error: UnimplementedError
at Object.throw_ [as throw] (errors.dart:266:49)
at firebase_crashlytics_service.FirebaseCrashlyticsService.new.recordException (firebase_crashlytics_service.dart:13:5)
at main.dart:26:23
at _RootZone.runBinary (zone.dart:1658:54)
at zone.dart:1800:17
at [_processUncaughtError] (zone.dart:1073:14)
at async._CustomZone.new.handleUncaughtError (zone.dart:1277:5)
at _Future._propagateToListeners (future_impl.dart:715:17)
at [_completeError] (future_impl.dart:574:5)
at future_impl.dart:665:7
at _rootRun (zone.dart:1391:13)
at async._CustomZone.new.run (zone.dart:1293:19)
at async._CustomZone.new.runGuarded (zone.dart:1201:7)
at async._AsyncCallbackEntry.new.callback (zone.dart:1241:23)
at Object._microtaskLoop (schedule_microtask.dart:40:11)
at _startMicrotaskLoop (schedule_microtask.dart:49:5)
at async_patch.dart:166:15

thanks.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.