1. Home
  2. Flutter Starter App
Flutter Starter App

If you starting a brand new app with Flutter - the auto-generated code is not usefull at all.
So I would show you how to create a more-or-less starter-ready app structure with some components each app should have nowadays.

Those components are 'localization' and 'Theme Provider'. We also make use of MaterialYou Navigation Bar and Tabs.

I am not going to make a details description of everything, it's pretty intuitive and the docu of single modules could be find on their github-pages

You can find the source code here: https://github.com/quadriq/flutter-starter-kit

Let's start

run to add those packages to pubspec.yaml

flutter pub add easy_localization
flutter pub add theme_provider

edit pubspec.yaml and adduncomment assets settings

  # To add assets to your application, add an assets section, like this:
  assets:
    - assets/i18n/

so now we are ready.. delete everything in lib folder and add those filestructure

lib/
  main.dart
  utils
     v.dart
  views/
    app/
       main_screen.dart
    home/
       home_tab.dart
    settings
       settings_tab.dart

Settings and Globals

we store them in utils/v.dart

class V {
  static const String VERSION = '0.0.1';

  static const String THEME_LIGHT = 'light';
  static const String THEME_DARK = 'dark';
}

Localizations

for usage of localizations first create a en.json file in assets/i18n folder. We would fill this with some translations. We would also use only english in our example.

{
  "app_name": "Starter App",

  "tab_home": "Home",
  "tab_settings": "Settings",

  "text_home": "Home",
  "text_settings": "Settings"
}

Coding

main.dart contains initialization of locales, themes, and calls the main App-View class MainScreen

import 'package:ballfoot/utils/v.dart';
import 'package:ballfoot/views/app/main_screen.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:theme_provider/theme_provider.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await EasyLocalization.ensureInitialized();
  runApp(
    EasyLocalization(
        supportedLocales: [
          Locale('en')
        ],
        fallbackLocale: Locale('en'),
        path: 'assets/i18n',
        child: MyApp()
    ),
  );
}


class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ThemeProvider(
      saveThemesOnChange: true,
      loadThemeOnInit: false,
      onInitCallback: (controller, previouslySavedThemeFuture) async {
        String? savedTheme = await previouslySavedThemeFuture;
        if (savedTheme != null) {
          print("DEBUG_ load saved theme");
          controller.setTheme(savedTheme);
        } else {
          print("DEBUG_ load new theme");
          Brightness platformBrightness =
              SchedulerBinding.instance.window.platformBrightness;
          if (platformBrightness == Brightness.dark) {
            controller.setTheme(V.THEME_DARK);
          } else {
            controller.setTheme(V.THEME_LIGHT);
          }
          controller.forgetSavedTheme();
        }
      },
      themes: <AppTheme>[
        AppTheme.dark(id: 'dark'),
        AppTheme.light(id: 'light'),
      ],
      child: ThemeConsumer(
        child: Builder(
          builder: (themeContext) => MaterialApp(
            debugShowCheckedModeBanner: false,
            theme: ThemeProvider.themeOf(themeContext).data,
            home: MainScreen(themeId: ThemeProvider.themeOf(themeContext).id),
            locale: context.locale,
            supportedLocales: context.supportedLocales,
            localizationsDelegates: context.localizationDelegates,
          ),
        ),
      ),
    );
  }
}

MainScreen is our main view class. Here how we make usage of NAvigationBar with some color adjustments:

bottomNavigationBar: NavigationBarTheme(
        data: NavigationBarThemeData(indicatorColor: Colors.red),
        child: NavigationBar(
          onDestinationSelected: (index) =>
              setState(() => _tabSelectedIndex = index),
          selectedIndex: _tabSelectedIndex,
          destinations: [
            NavigationDestination(
                icon: Icon(Icons.home), label: tr('tab_home')),
            NavigationDestination(
                icon: Icon(Icons.settings), label: tr('tab_settings')),
          ],
        ),
      )

and how we change between Dark/Light mode

_changeTheme(){
    var controller = ThemeProvider.controllerOf(context);
    if(ThemeProvider.themeOf(context).id == V.THEME_LIGHT){
      controller.setTheme(V.THEME_DARK);
      _themeIcon = Icons.dark_mode;
    } else {
      controller.setTheme(V.THEME_LIGHT);
      _themeIcon = Icons.light_mode;
    }
  }